F#中的并行处理

时间:2012-06-24 20:53:19

标签: concurrency f#

我在F#中玩async。这看起来是正确的,还是我纠结了什么?

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

1 个答案:

答案 0 :(得分:8)

首先,使用async并行CPU处理是一种反模式。有关详细信息,请参阅以下问题和解答:

Why shouldn't I use F# asynchronous workflows for parallelism?

Task Parallel Library vs Async Workflows

其次,您的fib函数应该重写为尾递归,这是here的示例(包括更改为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

请注意,在这两种情况下都会返回Array个结果,您只是将其丢弃在时间函数中。如果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)