F#:告诉我使用Async.Parallel时我缺少什么

Jon*_*tow 3 parallel-processing f#

好的,所以我正在做ProjectEuler问题#14,我正在摆弄优化以便感受f#out.

在以下代码中:

let evenrule n = n / 2L
let oddrule n = 3L * n + 1L

let applyRule n =
    if n % 2L = 0L then evenrule n
    else oddrule n

let runRules n =
    let rec loop a final =
        if a = 1L then final
        else loop (applyRule a) (final + 1L)
    n, loop (int64 n) 1L


let testlist = seq {for i in 3 .. 2 .. 1000000 do yield i } 

let getAns sq = sq |> Seq.head

let seqfil (a,acc) (b,curr) = if acc = curr then (a,acc) else if acc < curr then (b,curr) else (a,acc)

let pmap f l = 
    seq { for a in l do yield async {return f a} }
    |> Seq.map Async.RunSynchronously

let pmap2 f l = 
    seq { for a in l do yield async {return f a} }
    |> Async.Parallel
    |> Async.RunSynchronously

let procseq f l = l
                  |> f runRules
                  |> Seq.reduce seqfil
                  |> fst

let timer = System.Diagnostics.Stopwatch()
timer.Start()
let ans1 = testlist |> procseq Seq.map // 837799    00:00:08.6251990
printfn "%A\t%A" ans1 timer.Elapsed
timer.Reset()

timer.Start()
let ans2 = testlist |> procseq pmap
printfn "%A\t%A" ans2 timer.Elapsed // 837799   00:00:12.3010250
timer.Reset()

timer.Start()
let ans3 = testlist |> procseq pmap2
printfn "%A\t%A" ans3 timer.Elapsed // 837799   00:00:58.2413990
timer.Reset()
Run Code Online (Sandbox Code Playgroud)

为什么与直接映射相比,Async.Parallel代码运行速度非常慢?我知道我不应该看到那么大的影响,因为我只是在双核心mac上.

请注意,我不想帮助解决问题#14,我只是想知道我的并行代码是什么.

Tom*_*cek 9

使用Async.Parallel似乎是正确的.这些数字看起来很可疑,但我不会立即看到这里可能存在的问题.

在任何情况下,异步工作流实际上更适合涉及某些异步操作的计算(例如I/O,通信,等待事件等).对于CPU密集型任务,最好使用.NET的Parallel Extensions(现在是.NET 4.0的一部分;不幸的是,没有.NET 2.0版本).

要从F#中做到这一点,你需要F#PowerPackFSharp.PowerPack.Parallel.Seq.dll程序集,它包含用于处理序列的高阶函数的并行版本(例如map:-))

这些函数返回一个类型的值pseq<'a>(ParallelQuery<T>在C#中调用),它表示并行运行的延迟计算(这可以在管道中使用多个操作时实现更好的优化).还有PSeq.reduce功能,所以你可能也想在你的处理中使用它(除了PSeq.map).