我想在Haskell中编写一个尽可能高效的并行映射函数。我最初的尝试,似乎是目前最好的,只是写,
pmap :: (a -> b) -> [a] -> [b]
pmap f = runEval . parList rseq . map f
但是,我没有看到完美的CPU划分。如果这可能与火花的数量有关,我是否可以编写一个将列表分成#of cpus 段的pmap,因此创建了最少的火花?我尝试了下面这个,但是性能(和火花的数量)要差得多,
pmap :: (a -> b) -> [a] -> [b]
pmap f xs = concat $ runEval $ parList rseq $ map (map f) (chunk xs) where
-- the (len / 4) argument represents the size of the sublists
chunk xs = chunk' ((length xs) `div` 4) xs
chunk' n xs | length xs <= n = [xs]
| otherwise = take n xs : chunk (drop n xs)
性能较差可能与较高的内存使用率相关。最初的pmap确实在24核系统上有所扩展,所以并不是因为我没有足够的数据。 (我桌面上的CPU数量是4,所以我只是硬编码了。)
使用+RTS -H512m -N -sstderr -RTS
的一些效果数据来自:
答案 0 :(得分:9)
parallel包为您定义了许多并行地图策略:
parMap :: Strategy b -> (a -> b) -> [a] -> [b]
parList和map的组合,以及对列表进行分块的特定支持:
parListChunk :: Int -> Strategy a -> Strategy [a]
将列表划分为块,并将策略evalList strat
并行应用于每个块。
您应该能够使用这些组合来获得您想要的任何引发行为。或者,为了更多控制,the Par
monad包,用于控制创建的线程数量(纯粹)。