ok, so I'm doing ProjectEuler Problem #14, and I'm fiddling around with optimizations in order to feel f# out.
in the following code:
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()
Why does the Async.Parallel code run REALLY slow in comparison to the straight up map? I know I shouldn't see that much of an effect, since I'm only on a dual core mac.
Please note that I do NOT want help solving problem #14, I just want to know what's up with my parallel code.
The use of Async.Parallel
seems to be correct. The numbers really look suspicious, but I don't immediately see what may be a problem here.
In any case, asynchronous workflows are really more suitable for computations that involve some asynchronous operation (such as I/O, communication, waiting for events, etc.). For CPU intensive tasks, it is better to use Parallel Extensions to .NET (which are now a part of .NET 4.0; unfortunatelly there is no .NET 2.0 version).
To do that from F#, you'll need F# PowerPack and the FSharp.PowerPack.Parallel.Seq.dll
assembly, which contains parallel versions of higher-order functions for working with sequences (such as map
:-))
These functions return a value of type pseq<'a>
(called ParallelQuery<T>
in C#), which represent a delayed computation running in parallel (this enables better optimizations when you use multiple operations in pipeline). There is also PSeq.reduce
function, so you may want to use this in your processing too (aside from PSeq.map
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With