我有一个基本上做以下操作的计算机程序:
f :: [a] -> ([b],Bool)
实际上,这个函数可以被写成
f = foldr h ([],False) . map g
where h (b,bool) (bs,boolSoFar) = (b:bs,bool || boolSoFar)
其中 g :: a -> (b,Bool)
是一个需要花费很长时间的函数。而且f通常用于小列表,因此尝试使用并行计算来计算映射可能是有趣的。这可以通过Control.Parallel.Strategies中的parMap来实现。因此我们现在使用:
f = foldr h ([],False) . parMap rseq g
where h (b,bool) (bs,boolSoFar) = (b:bs, bool || boolSoFar)
这一切都很好。现在,您会注意到第一个f
的定义中可以执行顺序优化。也就是说,我可以使用映射折叠融合将其写为单个折叠,从而只需一次循环即可。但是,那样做就失去了并行化带来的好处。
现在,有人可能会说,在第二个f
的定义中再次循环列表并不那么糟糕,那为什么不直接这样做呢?我想的是,如果 Haskell 有可变变量,那么在 map 的主体中,就可以更新这个布尔变量(我想您需要锁定和解锁它)。有没有关于类似于这样做的建议?
g
被并行评估了吗,还是创建了thunks并让单核foldr
进行评估? - bheklilrmap
和parMap
之间的差别微不足道,而与使用Chans的差别则慢了一个数量级。这是一个很好的例子,说明GHC可以自己处理事情,而无需引入复杂的线程机制。 - bheklilr