4

私はasyncF#で遊んでいます。これは正しく見えますか、それとも私は物事をマングリングしていますか?

let time f = 
    let before = System.DateTime.Now
    f () |> ignore
    let after = System.DateTime.Now
    after - before;;

let rec fib = function 0 | 1 -> 1
                         | n -> fib (n - 1) + fib (n - 2);;

let source = [45; 40; 45; 40]

let synchronous = time <| fun () -> List.map fib source

let para = time <| fun () -> source
                             |> List.map (fun n -> async {ignore <| fib n}) 
                             |> Async.Parallel
                             |> Async.RunSynchronously

特に、asyncブロックから結果を返すにはどうすればよいですか?可変状態を使用する必要がありますか?

更新:ここに別のアプローチがあります:

#r "FSharp.PowerPack.Parallel.Seq.dll"
open Microsoft.FSharp.Collections

let pseq = time <| fun () -> source
                             |> PSeq.map fib
                             |> PSeq.toList
4

1 に答える 1

9

asyncまず、並列CPU処理に使用するのは少しアンチパターンです。詳細については、次の質問と回答を参照してください。

並列処理にF#非同期ワークフローを使用すべきではないのはなぜですか?

タスク並列ライブラリと非同期ワークフロー

次に、関数を末尾再帰になるように書き直す必要があります。ここfibからの例を次に示します(への変更を含む)。BigInt

let fib n =
    let rec loop acc1 acc2 = function
        | n when n = 0I -> acc1
        | n -> loop acc2 (acc1 + acc2) (n - 1I)
    loop 0I 1I n

最後に、完全なコード:

let source = [| 45I; 40I; 45I; 40I |]

let sync = time <| fun () -> Array.map fib source

let para = time <| fun () -> Array.Parallel.map fib source

どちらの場合も、結果の1つが返されることに注意してArrayください。これは、time関数に捨てるだけです。time時間と結果の両方を返す関数はどうですか?

let time f = 
    let watch = new System.Diagnostics.Stopwatch()
    watch.Start()
    let res = f ()
    watch.Stop()
    (res, watch.ElapsedMilliseconds)

使用法は同じままですが、結果が表示されます。

printfn "Sync: %A in %ims" (fst sync) (snd sync)
printfn "Para: %A in %ims" (fst para) (snd para)
于 2012-06-24T21:25:00.897 に答える