查看Haskell中并行和并发编程的以下示例:
main = do
[n] <- getArgs
let test = [test1,test2,test3,test4] !! (read n - 1)
t0 <- getCurrentTime
r <- evaluate (runEval test)
printTimeSince t0
print r
printTimeSince t0
test1 = do
x <- rpar (fib 36)
y <- rpar (fib 35)
return (x,y)
Run Code Online (Sandbox Code Playgroud)
这本书展示了它的编译:
$ ghc -O2 rpar.hs -threaded
Run Code Online (Sandbox Code Playgroud)
然后运行上面的测试:
$ ./rpar 1 +RTS -N2
time: 0.00s
(24157817,14930352)
time: 0.83s
Run Code Online (Sandbox Code Playgroud)
如果我理解正确中,eval单子(使用rpar)导致两个fib 36和fib 35并联被计算.
是否实际工作,即fib ... 在调用时计算功能(runEval test)?或许evaluate ...是必需的?或者,最后,也许在调用print r完全评估它时会计算出来?
目前尚不清楚对我来说,当实际工作获取执行rpar.
这是我的猜测,但我似乎无法在我的笔记本电脑上复制这个,我必须从cabal获得太多的进口.
test1 = do
x <- rpar (fib 36)
y <- rpar (fib 35)
return (x,y)
Run Code Online (Sandbox Code Playgroud)
在这一点上,你激发了评价(fib 36)和(fib 35)并行,但你不要等待它们 - 你只是(x,y)立刻回来,x而且y还在评估.然后,我们到达print r,你被迫等到x并y完成评估.
从理论上讲,下面的代码应强制test1等到x和y完成返回之前评估.
test1 = do
x <- rpar (fib 36)
y <- rpar (fib 35)
rseq x
rseq y
return (x,y)
Run Code Online (Sandbox Code Playgroud)
那么,运行它应该给你大概
$ ./rpar 1 +RTS -N2
time: 0.83s
(24157817,14930352)
time: 0.83s
Run Code Online (Sandbox Code Playgroud)
希望...
最后回到我的机器,复制了条件,我的建议代码给出了预期的结果.然而,OP提出了另一个好问题:如果evaluate仅评估WHNF,为什么它甚至会在调用print之前完成工作?
答案是在monad定义中Control.Parallel.Strategies- 换句话说,它并不是evaluate推动评估x和y,而是runEval.该Eval单子是在第一个参数严格:在x >>= f将评估x(请看看这个问题,然后再继续).然后,脱糖test1给出:
test1 = (rpar (fib 36)) >>= (\x ->
(rpar (fib 35)) >>= (\y ->
(rseq x) >>= (\_ ->
(rseq y) >>= (\_ ->
return (x,y)))))
Run Code Online (Sandbox Code Playgroud)
然后,由于rpar只有"火花"评估,它使用par(开始评估第一个参数但立即返回第二个参数)并立即返回Done,但是,rseq(例如seq,但仅在第一个参数中严格)不会返回,Done直到其参数为实际评估(对WHNF).因此,在没有rseq调用的情况下,您已经知道x并且y已经开始被评估但不能保证它们已经完成,但是通过这些调用,您知道它们x并且y在return被调用它们之前也被评估.