我正在玩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
Run Code Online (Sandbox Code Playgroud)
特别是,如何从async块中返回结果?我必须使用可变状态吗?
更新:这是另一种方法:
#r "FSharp.PowerPack.Parallel.Seq.dll"
open Microsoft.FSharp.Collections
let pseq = time <| fun () -> source
|> PSeq.map fib
|> PSeq.toList
Run Code Online (Sandbox Code Playgroud)
首先,它是async用于并行CPU处理的一种反模式.有关更多信息,请参阅以下问题和答案:
其次,你的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
Run Code Online (Sandbox Code Playgroud)
最后,完整的代码:
let source = [| 45I; 40I; 45I; 40I |]
let sync = time <| fun () -> Array.map fib source
let para = time <| fun () -> Array.Parallel.map fib source
Run Code Online (Sandbox Code Playgroud)
请注意,在这两种情况下Array都会返回一个结果,您只是将其丢弃在时间函数中.一个time返回时间和结果的函数怎么样?
let time f =
let watch = new System.Diagnostics.Stopwatch()
watch.Start()
let res = f ()
watch.Stop()
(res, watch.ElapsedMilliseconds)
Run Code Online (Sandbox Code Playgroud)
用法保持不变,但现在显示结果:
printfn "Sync: %A in %ims" (fst sync) (snd sync)
printfn "Para: %A in %ims" (fst para) (snd para)
Run Code Online (Sandbox Code Playgroud)