randomInts是否患有乒乓球效应?

时间:2014-03-30 21:13:31

标签: haskell random

以下两个代码来自RWH书的并发章节:

force :: [a] -> ()
force xs = go xs `pseq` ()
    where go (_:xs) = go xs
          go [] = 1

randomInts :: Int -> StdGen -> [Int]
randomInts k g = let result = take k (randoms g)
                 in force result `seq` result

randomInts是用于生成用于测试并行排序算法性能的随机数列表的函数。书中已经提到它们避免了上述代码中的一些潜在问题。这就是书中所说的:

  

不可见的数据依赖性。

     

当我们生成随机数列表时,只需打印   列表的长度不会执行足够的评估。这个啰嗦   评估列表的主干,但不评估其元素。实际上   在排序比较之前,不会评估随机数。

     

这可能会对性能产生严重影响。 a的价值   随机数取决于前一个随机数的值   列表,但我们已经将列表元素随机分散在我们的列表中   处理器核心。如果我们之前没有评估列表元素   排序,我们会遭受可怕的“乒乓”效应:不仅会   评估从一个核心反弹到另一个核心,性能会受到影响。

     

尝试从主体上方剪断力的施加:   你会发现并行代码很容易就会结束三次   比非并行代码慢。

所以基本上他们说通过使用force函数他们避免了乒乓问题。但在解释force函数时,他们再次描述它:

  

请注意,我们并不关心列表中的内容;我们走下脊柱   到最后,然后使用pseq一次。显然没有任何魔法   在这里:我们只是使用我们对Haskell的常规理解   评估模型。因为我们将在左手使用武力   par或pseq的一面,我们不需要返回有意义的值。

force函数的定义和上面的解释可以看出,不评估各个列表元素中的元素。那么randomInts函数如何实际上避免了ping-pong效应。这是书中的错误还是我理解错误?

1 个答案:

答案 0 :(得分:0)

randomInts实际上似乎没有ping-pong效果。函数force实际上不仅遍历列表的整个样条曲线,而且还评估列表的元素。

import Control.Parallel (par, pseq)

force :: [a] -> ()
force xs = go xs `pseq` ()
  where go (_:xs) = go xs
        go [] = 1

在ghci:

ghci > let a = [1..10]
ghci > :sprint a
a = _
ghci > force a
()
ghci > :sprint a
a = [1,2,3,4,5,6,7,8,9,10]

因此force函数会完全评估列表,从乒乓效应中保存它。