Mam wdrożenie gry życia Conwaya. Chcę go przyspieszyć, jeśli to możliwe, używając paralelizmu.Haskell parMap i paralelizm
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]
w profilowaniu, sąsiedzi stanowi 6,3% czasu spędzonego, więc podczas gdy małe spodziewałem się zauważalne przyspieszenie przez odwzorowanie go równolegle.
I badane w funkcji prostego
main = print $ last $ take 200 $ iterate life fPent
where fPent = [(1, 2), (2, 2), (2, 1), (2, 3), (3, 3)]
i zebrane wersję równoległym
ghc --make -O2 -threaded life.hs
i uruchomiono go jako
./life +RTS -N3
okazuje się, że wersja równoległego jest mniejsza . Czy używam tutaj niepoprawnej mapy? czy jest to nawet przypadek, w którym można zastosować paralelizm?
Po pierwsze, masz co najmniej 3 rdzenie w swoim komputerze? Po drugie, równoległość zawsze wiąże się z pewnym obciążeniem, więc jeśli praca wykonywana przez każdy wątek jest bardzo mała, dodatkowe obciążenie będzie większe niż jakiekolwiek przyspieszenia. – huon
Mam i5-2500k, więc jest zdecydowanie do 4 rdzeni dostępnych – cdk
Zauważ, że możesz uzyskać znacznie większe przyspieszenia od ulepszenia algorytmu niż zrównoleglania. Większość czasu spędza się w 'sort' i' elem'. Wykorzystując fakt, że lista komórek jest sortowana (i zmienia się 'fPent', aby była sortowana), można z grubsza zmniejszyć o połowę czas. –