Haskell:为什么顺序运行?

时间:2018-05-27 14:41:33

标签: haskell parallel-processing

美好的一天。给定代码

import           Control.DeepSeq
import           Control.Exception
import           Control.Parallel
import           Control.Parallel.Strategies
import           System.Environment
import           Text.Printf

l = [34,56,43,1234,456,765,345,4574,58,878,978,456,34,234,1234123,1234,12341234]
f x = Just (sum [1..x])

fun1 :: [Maybe Integer]
fun1 = map f l `using` parList rdeepseq
fun2 :: [Maybe Integer]
fun2 = map f l `using` evalList (rparWith rdeepseq)
fun3 :: [Maybe Integer]
fun3 = map f l `using` evalList (rpar . force)

main :: IO ()
main = print fun1

为什么fun1fun2按顺序运行? 根据我的理解,rparWith应引发其争论。答案here表示相同。但是对于fun1和fun2,我得到的输出就像" SPARKS:0(0转换,0溢出,0哑,0 GC' d,0失败)"。所以Spark甚至没有创建。 fun3按预期工作,创建火花。 Ty寻求帮助

UPD:我发现rdeepseq在书中(Haskell中的并行和并发编程)的例子按顺序工作。书说:

  

我们可以使用parPair编写一个策略来并行完全评估一对组件:

     

parPair rdeepseq rdeepseq ::(NFData a,NFData b)=>策略(a,b)

     

要分解将此策略应用于一对时发生的情况:parPair调用,并且evalPair在该对的每个组件上调用rparWith rdeepseq。所以   效果是每个组件将被平行完全评估为正常形式。

但如果我跑

(Just (fib 35), Just (fib 36)) `using` parPair rdeepseq rdeepseq

甚至

(fib 35, fib 36) `using` parPair rdeepseq rdeepseq

Threadscope只显示一个核心运行并创建了0个火花。

fib这样实现(也来自书)

fib :: Integer -> Integer
fib 0 = 1
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

2 个答案:

答案 0 :(得分:0)

The original paper describes rdeepseq as

rdeepseq :: NFData a => Strategy a
rdeepseq x = rnf x ‘pseq‘ return x

And indeed, if you use this definition, it will create sparks, like you'd expect. Looks like rdeepseq sematrics was changes (probably here), intentionally or incidentally. I don't see any note neither in the documentation, nor in the changelog, so it is probably a bug. Please create at issue on their bug tracker and ask maintainers for clarification.

答案 1 :(得分:0)

rparWith是使用realWorld#定义的,它是GHC极具魔力的内部价值。它的使用方式基本上与应用有时称为accursedUnutterablePerformIO的“功能”(更正式地说是unsafeInlinePerformIO)相同。仅在所讨论的IO实际上非常纯净时才使用它。当时的想法是,由于Eval仅用于计算,所以应该没问题。但是实际上,激发线程是一种IO的效果,我们很在乎!优化器以不幸的方式重新排列了这些效果,最终导致它们被丢弃。解决方法是改用unsafeDupablePerformIO。这是一个表现更好的“功能”,似乎可以解决问题。有关详细信息,请参见the ticket

注意:我的最初修复结果有误;现在已被再次修改。