在Haskell / GHC中驯服并行性

时间:2016-12-17 13:43:51

标签: haskell parallel-processing ghc

关于使并行性有效运行的问题,Haskell新手问道。

Advent of Code Day 14挑战涉及创建一系列整数的MD5哈希值,寻找给出哈希值满足某些属性的前n个整数。我基本上是通过创建哈希然后过滤它们来实现的。

我认为尝试使用并行机会是一件好事,使用多个内核来生成哈希值。

哈希创建的非并行版本如下所示:

md5sequenceS :: [String]
md5sequenceS = [makeMd5 i | i <- [0..]]
    where makeMd5 i = stretch $ getHash (salt ++ show i)
          stretch h0 = foldr (\_ h -> getHash h) h0 [1..2016]

......它工作得很好,虽然很慢,但在大约四分钟内给出答案。

并行版本如下所示:

md5sequenceS :: [String]
md5sequenceS = parMap rdeepseq (makeMd5) [0..]
    where makeMd5 i = stretch $ getHash (salt ++ show i)
          stretch h0 = foldr (\_ h -> getHash h) h0 [1..2016]

...除了parMap rdeepseq位之外与之前相同。这不能正常工作:它会消耗我机器上的所有可用内存,并且在30分钟的待机时间后仍然无法产生答案。但是,它确实完全使用了所有处理器。

我该怎样做才能驯服这种失控的并行性?

(问题规范没有提供我需要生成多少哈希的任何线索,但事实证明我需要大约30,000个整数哈希值。)

修改以包含已接受的答案

parBuffer策略可以用作

md5sequenceS = withStrategy (parBuffer 100 rdeepseq) $ map (makeMd5) [0..]
    where makeMd5 i = stretch $ getHash (salt ++ show i)
          stretch h0 = foldr (\_ h -> getHash h) h0 [1..2016]

与单线程版本相比,性能不是很好,但这是一个不同的问题......

1 个答案:

答案 0 :(得分:3)

parMap将强制评估所有列表,在您的情况下是无限的。

您可以考虑使用其他策略,例如parBuffer来处理无限列表,而不是使用parMap