2012-09-01 36 views
9

我有一個Conway的生命遊戲的實現。如果可能的話,我想通過使用並行性來加速它。Haskell parMap和並行性

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%,因此,雖然小我期望的noticable加速通過並聯映射它。

我用一個簡單的函數

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嗎?這是甚至可以使用並行性的情況嗎?

+0

首先,你的計算機至少有3個內核?其次,並行性總是會帶來一些開銷,所以如果每個線程所做的工作都非常小,額外的開銷將超過任何加速。 – huon

+0

我有一個i5-2500k,所以肯定有多達4個內核可用 – cdk

+0

請注意,您可以從改進算法中獲得比並行化更大的加速。大部分時間都花在'sort'和'elem'上。使用單元格列表進行排序(並更改'fPent'以便對它進行排序)這一事實,可以大致減半時間。 –

回答

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

+0

嗯,奇怪。我還得到了parLife比標準更快的結果,但是當我單獨運行這個東西時,parLife始終比「life」慢得多。 –

+0

啊,只有在線程運行時,不能與非線程! –

+0

我認爲這與這個過程的長壽有關......也就是說,初始化線程池等比我們從並行化中獲得的收益(固然微不足道)要昂貴。 –