我在玩 async
在 F# 中。这看起来对吗,还是我在破坏东西?
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
最佳答案
首先,使用 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)
关于concurrency - F#中的并行处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11181109/