4

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
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

请注意,在这两种情况下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)
于 2012-06-24T21:25:00.897 回答