
On Tue, 2008-12-23 at 18:27 +0000, Paul Keir wrote:
Hi Duncan,
I'm following the story regarding (parallel) GC in this example with interest, but forgive me if I ask a more minor question regarding your modification of an extra parameter, "n", to "heavytask". Does this really help (to ensure that each core does work independently)? Surely, with fibs now described in a where clause, the "0:1:etc." form would not be shared among the (8) instantiations of "heavytask"?
Yes, that was the purpose of the modification, to ensure that the value was not shared but calculated independently. I wanted to test speedup with a trivially parallel workload. If the value really is shared then there will necessarily be no speedup. That is because the definition of this value does not use any explicit parallelism and ghc does not do any automatic parallelisation. Demanding the same evaluation from multiple threads just causes the other threads to block awaiting evaluation.
heavytask m n = putMVar m $! (fibs !! 100000) where fibs = n : (n+1) : zipWith (+) fibs (tail fibs)
To get parallel speedup when evaluating a single value like this we need a different definition. We could use IO threads with forkIO and explicit shared variables or message passing. However since this is a pure function a much nicer approach is to use a pure implementation using the `par` operator: http://darcs.haskell.org/nofib/parallel/parfib/Main.hs -- parallel version of the code with thresholding parfib :: Int -> Int -> Int parfib n t | n <= t = nfib n | otherwise = n1 `par` (n2 `pseq` n1 + n2 + 1) where n1 = parfib (n-1) t n2 = parfib (n-2) t Using `par` creates "sparks" which are even lighter weight than Haskell IO threads. They are just values/thunks and get evaluated by a pool of ordinary Haskell threads. Duncan