Haskell的parMap性能如何?

5

我试图用一个非常简单的例子来比较parMap和map的性能:

import Control.Parallel.Strategies
import Criterion.Main

sq x = x^2

a = whnf sum $ map sq [1..1000000]
b = whnf sum $ parMap rseq sq [1..1000000]

main = defaultMain [
    bench "1" a,
    bench "2" b
  ]

我的结果似乎表明使用parMap没有加速,我想知道这是为什么?

benchmarking 1
Warning: Couldn't open /dev/urandom
Warning: using system clock for seed instead (quality will be lower)
time                 177.7 ms   (165.5 ms .. 186.1 ms)
                     0.997 R²   (0.992 R² .. 1.000 R²)
mean                 185.1 ms   (179.9 ms .. 194.1 ms)
std dev              8.265 ms   (602.3 us .. 10.57 ms)
variance introduced by outliers: 14% (moderately inflated)

benchmarking 2
time                 182.7 ms   (165.4 ms .. 199.5 ms)
                     0.993 R²   (0.976 R² .. 1.000 R²)
mean                 189.4 ms   (181.1 ms .. 195.3 ms)
std dev              8.242 ms   (5.896 ms .. 10.16 ms)
variance introduced by outliers: 14% (moderately inflated)

Square 几乎是一个无操作。尝试并行执行它并没有真正带来任何好处。 - Cubic
@Cubic 我原本的印象是它会将列表的不同部分分配给不同的线程,从而让每个线程的操作数量有效减少。 - allidoiswin
1个回答

7
问题在于parMap为每个列表元素启动一个并行计算。正如你在评论中所说,它不会将列表分块,这需要使用parListChunk策略。
因此,parMap的开销很高,每个Spark仅平方一个数字的事实意味着其成本被开销淹没。

3
平方计算如此廉价,以至于我猜测在 parListChunk 中进行列表分割也会压倒并行收益。 - András Kovács
3
并行化会降低融合效率,否则将带来数量级的加速。 - András Kovács
@AndrásKovács:确实。当我并行化我的一个程序(使用parBuffer)时,我观察到了这种情况。该程序计算输入数据的一系列统计函数,其中一些比其他函数更昂贵。因此,它使快速函数变慢,以换取大大加快慢函数的代价。只需付出最小的努力。 - Luis Casillas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接