Haskell parMap和并行

时间:2012-09-01 04:15:27

标签: haskell parallel-processing conways-game-of-life

我实施了康威的生命游戏。我希望通过使用并行性来加速它。

life :: [(Int, Int)] -> [(Int, Int)]
life cells = map snd . filter rules . freq $ concatMap neighbours cells
    where rules (n, c) = n == 3 || (n == 2 && c `elem` cells)
          freq = map (length &&& head) . group . sort

parLife :: [(Int, Int)] -> [(Int, Int)]
parLife cells = parMap rseq snd . filter rules . freq . concat $ parMap rseq neighbours cells
    where rules (n, c) = n == 3 || (n == 2 && c `elem` cells)
          freq = map (length &&& head) . group . sort

neigbours :: (Int, Int) -> [(Int, Int)]
neighbours (x, y) = [(x + dx, y + dy) | dx <- [-1..1], dy <- [-1..1], dx /= 0 || dy /= 0]

在分析中,邻居占用了花费的时间的6.3%,所以虽然很小,但我通过并行映射来预期显着的加速。

我测试了一个简单的功能

main = print $ last $ take 200 $ iterate life fPent
    where fPent = [(1, 2), (2, 2), (2, 1), (2, 3), (3, 3)]

并将并行版本编译为

ghc --make -O2 -threaded life.hs

并将其作为

运行
./life +RTS -N3

事实证明并行版本较慢。我在这里错误地使用parMap吗?这甚至是可以使用并行性的情况吗?

1 个答案:

答案 0 :(得分:2)

我认为你的测量不对。您的parLife确实比life快一点。事实上,在我的机器上(Phenom X4,4核心),前者仅占用后者的92.5%,考虑到你说你期望只有6%的改善是相当不错的。

您的基准测试设置是什么?您是否尝试过使用criterion?这是我做的:

import Criterion
import Criterion.Main

-- your code, minus main

runGame f n = last $ take n $ iterate f fPent
    where fPent = [(1, 2), (2, 2), (2, 1), (2, 3), (3, 3)]

main = defaultMain
    [ bench "No parallelism 200" $ whnf (runGame life)    200
    , bench "Parallelism 200"    $ whnf (runGame parLife) 200 ]

使用ghc --make -O2 -o bench进行了编译,并使用./bench -o bencht.hmtl +RTS -N3进行了投放。

Here's the detailed result of the report