[Haskell-cafe] parallel Haskell

Dennis Raddle dennis.raddle at gmail.com
Thu Jul 6 16:53:34 UTC 2017


I have a program which does backtracking search in a recursive function.  I
followed the chapter in "Real World Haskell" to parallelize it.

Without Control.Parallel, it uses about 25% of the CPU, namely one core out
of four. With the suggestions in RWH it runs faster but still uses only 35%
of the CPU max.

So I set about creating a MWE in order to experiment and reach out for
help. For some reason, my stripped down program isn't working with
parallelism at all!

There's no effect from the R.W.H. ideas. Can I get some suggestions as to
why?

Here's the program:
--------------------------------------------
import qualified Data.List as L
import Text.Printf
import System.CPUTime
import Data.Function
import Control.Parallel

-- Run backtracking search for a list of doubles, optimizing a
-- fitness function on the list, called 'evalFunc'. At each step, use
'stepFunc'
-- to generate a list of possible next Doubles that can be added to the
list.
-- We are done when the list has 'finalSize' elements.
search1_par :: Int ->
  ([Double] -> Double) -> ([Double] -> [Double]) -> [Double] ->
(Double,[Double])
search1_par finalSize evalFunc stepFunc listIn
  | length listIn == finalSize = (evalFunc listIn,listIn)
  | otherwise =
      let steps = stepFunc listIn
          (steps1,steps2) = divideListInTwo steps
          f s = search1_par finalSize evalFunc stepFunc $ s:listIn
          results1 = map f steps1
          results2 = map f steps2
          results = force results1 `par` (force results2 `pseq`
(results1++results2))
      in L.maximumBy (compare `on` fst) results

force :: [a] -> ()
force xs = go xs `pseq` ()
  where go (_:xs) = go xs
        go [] = 1

divideListInTwo :: [a] -> ([a],[a])
divideListInTwo [] = ([],[])
divideListInTwo xs = (take l xs,drop l xs) where l = length xs `div` 2

---------------------------------------------
-- some sample evaluation (fitness) functions and step generation functions.

eval1 :: [Double] -> Double
eval1 xs = v1 - v2 + v3
  where
    v1 = sum $ zipWith (*) (cycle [1]) xs
    v2 = sum . map (*2) $ zipWith (*) (cycle [1,0]) xs
    v3 = sum . map (*3)  $ zipWith (*) (cycle [1,0,0]) xs


step1 :: [Double] -> [Double]
step1 xs | l == 0 = take 8 $ xs
         | l == 1 = take 8 $ map (/2) xs
         | l == 2 = take 8 $ map (*3) xs
  where
    l = length xs `mod` 3
--------------------------------------------------------------------------------
-- main

main = do
  t1 <- getCPUTime
  let f :: Double -> String
      f x = printf "%5.1f" x
      (_,result) = search1_par 13 eval1 step1 [1,2,3]
  putStrLn $ concatMap f result
  t2 <- getCPUTime
  putStrLn $ printf "CPU time: %.3f" ((fromIntegral $ t2-t1) /
1000000000000 :: Double)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20170706/3a986324/attachment.html>


More information about the Haskell-Cafe mailing list