美好的一天。给定代码
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
为什么fun1
和fun2
按顺序运行?
根据我的理解,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)
答案 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。
注意:我的最初修复结果有误;现在已被再次修改。