2010-02-26 10 views
2

방금 ​​F #으로 어지럽게 시작했고 언어에 익숙해지기 위해 몇 가지 기본 병렬 계산을 시도하고 있습니다. 유형 불일치에 문제가 있습니다. 다음 예는 다음과 같습니다Async in F in #

let allVariances list = 
    seq { 
     for combination in allCombinations list do 
      yield (combination, abs(targetSum - List.sum combination)) 
    } 

let compareVariance tup1 tup2 = 
    if snd tup1 < snd tup2 then 
     tup1 
    else 
     tup2 

let aCompareVariance tup1 tup2 = 
    async { return compareVariance tup1 tup2 } 

let matchSum elements targetSum = 
    allVariances elements 
    |> Seq.reduce aCompareVariance 
    |> Async.Parallel 
    |> Async.RunSynchronously 

그래서, "allVariances 요소"는 서열 <float list * float을 생산>. CompareVariance는 그 중 두 개를 취하고 더 작은 두 번째 항목 (분산)을 가진 하나를 반환합니다. 내 목표는 Reduce를 사용하여 가장 작은 차이가있는 튜플로 끝나는 것입니다. 그러나 aCompareVariance 인수가 형식이 일치하지 않습니다.

오류 1 형식이 일치하지 않습니다. float -> float list * float -> float list * float -> float list * float -> float list * float -> Async <float list * float> 'float list * float'유형이 ' 비동기 <float list * float> '

Reduce에서 비동기 반환 유형을 허용하지 않는 것 같습니다.

답변

2

Seq.reduce은 함수와 시퀀스를 취하여 함수를 사용하여 목록을 줄입니다. 즉, 시퀀스 {a1;a2;a3;...;an}f으로 줄이면 결과는 f(f(...f(f(a1,a2),a3),...),an))...)이됩니다. 그러나 반환 형식 (Async<float list * float>)이 인수 형식 (float list * float)과 일치하지 않으므로 전달중인 함수를이 방법으로 적용 할 수 없습니다. 정확히 당신이 성취하고자하는 것은 무엇입니까?

또한 async 연산은 비동기식 작업에 적합하지만 병렬 작업용으로는 이상적이지 않습니다. F#: Asynch and Tasks and PLINQ, oh my!Task Parallel Library vs Async Workflows을 참조하십시오.

편집

여기에 당신이 예상처럼 같은 종류의 운영, 더 많은 항목을 줄일 함수 작성하는 하나 개의 방법 : 각 단계에서

[|a1; a2; a3; a4|] 
[|f a1 a2; f a3 a4|] 
f (f a1 a2) (f a3 a4) 

이, F의 모든 응용 프로그램이 소요됩니다 병렬로 배치하십시오. 이것은 Async.Parallel을 사용합니다. 위에서 언급했듯이 작업 병렬 라이브러리를 사용하는 것보다 적절하지 않을 수도 있습니다 (정상적인 동기 Array.reduce을 수행하는 것보다 느릴 수도 있음). 따라서 비동기 함수를 함께 처리하는 방법을 보여주는 데모 코드로 간주하십시오. 와 Async 값에서 항목을 변환하는 것은 모두이 함수 내부에서 일어나는, 그래서 Array.reduce와 같은 형태를 가지고 있으며, 여러분의 정상 compareVariance 기능보다는 aCompareVariance으로 사용되는 것을

let rec reduce f (arr:_[]) = 
    match arr.Length with 
    | 0 -> failwith "Can't reduce an empty array" 
    | 1 -> arr.[0] 
    | n -> 
     // Create an array with n/2 tasks, each of which combines neighboring entries using f 
     Array.init ((n+1)/2) 
     (fun i -> 
      async { 
      // if n is odd, leave last item alone 
      if n = 2*i + 1 then 
       return arr.[2*i] 
      else 
       return f arr.[2*i] arr.[2*i+1]}) 
     |> Async.Parallel |> Async.RunSynchronously 
     |> reduce f 

참고.

+0

나는 감소에 대해 잘못된 생각을 가지고 있었다고 생각합니다. 시퀀스 {a1; a2; a3; a4} : f (f (a1, a2), f (a3, a4))에 대해 이와 같이 작동하기를 바랬습니다. 이렇게 실행되면 f (a1, a2)와 f (a3, a4)가 동시에 실행될 수 있습니다. –

+0

@ user282232 -이 경우에도 가장 바깥 쪽'f'가 이전 축소 단계의 출력에 작용하기 때문에'f'에 대한 입력 및 출력 유형이 일치해야합니다. – kvb

+0

그렇다면 왜 그 유형이 일치하지 않습니까? '는 그것이 다른 스레드에서 왔는지 또는 같은 스레드에서 오는지 여부입니다. –