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中的并行映射的主要内容,如果未能解决你的问题,请参考以下文章

Haskell 中的半显式并行

为啥 Haskell 中没有隐式并行性?

基于 Haskell 中的字符串映射证明打印函数的穷举性

在 Haskell 中使用并行策略时速度变慢

如何在haskell快速傅里叶变换中应用数据并行?

如何在 Haskell 中表示两棵树之间的映射?