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,我只是想知道我的并行代码是什么.
使用Async.Parallel似乎是正确的.这些数字看起来很可疑,但我不会立即看到这里可能存在的问题.
在任何情况下,异步工作流实际上更适合涉及某些异步操作的计算(例如I/O,通信,等待事件等).对于CPU密集型任务,最好使用.NET的Parallel Extensions(现在是.NET 4.0的一部分;不幸的是,没有.NET 2.0版本).
要从F#中做到这一点,你需要F#PowerPack和FSharp.PowerPack.Parallel.Seq.dll程序集,它包含用于处理序列的高阶函数的并行版本(例如map:-))
这些函数返回一个类型的值pseq<'a>(ParallelQuery<T>在C#中调用),它表示并行运行的延迟计算(这可以在管道中使用多个操作时实现更好的优化).还有PSeq.reduce功能,所以你可能也想在你的处理中使用它(除了PSeq.map).