Reputation: 2589
Following the examples in Chapter 24 of "Real World Haskell" and Chapter 2 of "Parallel and Concurrent Programming in Haskell", I've managed to build the following functions for building and traversing a binary tree quickly using multiple processors.
import Control.Parallel (par, pseq)
import Control.DeepSeq
data Tree x = Empty | Node x (Tree x) (Tree x) deriving (Show, Read, Eq)
-- Create instance of NFData for Tree data type (defining "normal form")
instance NFData a => NFData (Tree a) where
rnf Empty = ()
rnf (Node x l r) = rnf x `seq` rnf l `seq` rnf r
-- Recursive function to build a tree using multiple processors simultaneously
copyBoxPar :: Int -> Tree Int
copyBoxPar x
| x <= 0 = Empty
| x > 0 = force left `par` (force right `pseq` (Node x (left)(right)))
where
left = copyBoxPar (x-1)
right = copyBoxPar (x-1)
-- Serial recursive function to count leaves in tree
countBoxes :: Tree x -> Int
countBoxes Empty = 0
countBoxes (Node x left right) = 1 + countBoxes (left) + countBoxes (right)
I can verify that using the functions above, there is a more than 2x speedup using 6 CPUs, compared to the serial equivalent.
However, I'd like to speed this up more if I can.
It seems to me that implementing a parallel version of the countBoxes function should help, but when I try to replace the definition of countBoxes with the parallel code below, I get an error "No instance for (NFData x) arising from a use of 'force'".
-- Parallel function to count leaves in tree
countBoxes :: Tree x -> Int
countBoxes Empty = 0
countBoxes (Node x left right) = force left `par` (force right `pseq` (1 + countBoxes (left) + countBoxes (right)))
Should I really expect a speedup? How can I implement this? Any other advice on streamlining this code would be appreciated.
Upvotes: 0
Views: 470
Reputation: 24166
Your parallel countBoxes
needs an NFData (Tree x)
instance to use force
on the Tree x
s left
and right
. You can require that one exists by adding NFData x
to the context for the type signature for countBoxes
.
-- Parallel function to count leaves in tree
countBoxes :: NFData x => Tree x -> Int
...
NFData x
is enough to deduce NFData (Tree x)
from due to your instance NFData a => NFData (Tree a)
.
I suggest you try running this to see how it affects performance. Perhaps a parallel countBoxes
shouldn't need to be able to force
an entire tree ...
Upvotes: 2