haskell中的并行映射
Posted
技术标签:
【中文标题】haskell中的并行映射【英文标题】:Parallel map in haskell 【发布时间】:2011-08-02 03:30:49 【问题描述】:是否有一些 map
的替代品可以并行评估列表?我不需要它偷懒。
类似:pmap :: (a -> b) -> [a] -> [b]
让我 pmap expensive_function big_list
并让我所有的核心都达到 100%。
【问题讨论】:
【参考方案1】:除了像 Tom 所描述的那样自己使用显式策略之外,parallel 包 also exports parMap
:
parMap :: Strategy b -> (a -> b) -> [a] -> [b]
策略参数类似于rdeepseq
。
par-monad 包中还有 parMap
(你走出纯 Haskell,进入并行 monad):
parMap :: NFData b => (a -> b) -> [a] -> Par [b]
par-monad 包是documented here。
【讨论】:
这里有一个小警告。 parMap 使用的是严格的 mapM。这意味着列表脊椎在计算开始之前被完全评估 - 如果列表很长,例如您正在对从(巨大)文件中读取的记录进行 parMap'ping,这可能不是您想要的。也许这对惰性 parMap 或通过循环分发元素会更好。【参考方案2】:是的,见parallel package:
ls `using` parList rdeepseq
将通过rdeepseq
策略并行评估列表中的每个元素。请注意,如果您的元素太便宜而无法获得并行评估每个元素的好处(因为它可以节省每个元素的火花),则使用具有良好块值的 parListChunk
可能会提供更好的性能。
编辑:根据您的问题,我觉得我应该解释为什么这是一个答案。这是因为 Haskell 很懒!考虑声明
let bs = map expensiveFunction as
没有进行任何评估。您刚刚创建了一个映射 expensiveFunction
的 thunk。那么我们如何并行评估呢?
let bs = map expensiveFunction as
cs = bs `using` parList rdeepseq
现在不要在以后的计算中使用bs
列表,而是使用cs
列表。 IOW,您不需要并行映射,您可以使用常规(惰性)映射和并行评估策略。
编辑:如果您环顾四周,您会看到 parMap 函数,它执行我在此处显示的操作,但封装在一个辅助函数中。
针对您的评论,以下代码对您不起作用吗?它对我有用。
import Control.Parallel.Strategies
func as =
let bs = map (+1) as
cs = bs `using` parList rdeepseq
in cs
【讨论】:
我试过pmap f x = (map f x) `using` parList rdeepseq
,但 GHC 抱怨 rdeepseq 需要一个参数。
@clark 查看我粘贴的代码 - 这应该可以很好地加载到 GHCi 中。对你起作用吗?表达式parMap rdeepseq f as
应该做同样的事情。
对我不起作用。 “没有因使用 `rdeepseq' 而导致 (Control.DeepSeq.NFData b) 的实例”
@clark 您必须在特定上下文中使用它或使用显式类型签名。确保列表中的元素具有NFData
实例——这是使用rdeepseq
所必需的。如果这太繁琐,那么请改用rseq
,它会评估为 whnf。
@clark 您是否使用线程 (ghc -O2 -threaded blah.hs --make
) 进行编译并使用正确的 RTS 选项 (./blah +RTS -Nx
) 其中 x
是您要使用的内核数,例如 2
?请注意,在 GHC 7 上,您应该只能输入 ghc -O2 -threaded -with-rtsopts=-N blah.hs
并运行 ./blah
。以上是关于haskell中的并行映射的主要内容,如果未能解决你的问题,请参考以下文章