У меня есть реализация игры жизни Конвея. Я хочу ускорить его, если это возможно, используя параллелизм.
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? это даже случай, когда можно использовать параллелизм?
sort
иelem
. Используя тот факт, что список ячеек отсортирован (и изменивfPent
так, чтобы он был отсортирован), вы можете сократить время примерно вдвое. - person Daniel Fischer   schedule 01.09.2012freq = map (length &&& head) . group . sort
, поэтомуcells
для следующего поколения всегда сортируются. - person Daniel Fischer   schedule 08.09.2012