何时rpar和rseq表达式实际上是在Haskell程序中计算的?

时间:2015-12-15 05:42:39

标签: haskell parallel-processing

考虑以下计划。

import Control.Parallel
import Control.Parallel.Strategies

main = do
    r <- evaluate (runEval test)
    print r

test = do
    a <- rpar (fib 36)
    b <- rpar (fib 37)
    return (a,b)

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

请注意,我们故意使用Fibonacci生成器的低效实现来进行计算需要一些时间。现在我们用GHC编译这个程序:

$ ghc rpar.hs -threaded

该程序带有+RTS -N1标志的 3.281s ,带有+RTS -N2标志的 2.126s 。现在我们将print r替换为print "hello"函数中的main,并以相同的方式编译修改后的程序。新计划的+RTS -N1 0.003s +RTS -N2 0.004s 。似乎a函数中的btest未在新程序中计算。

然后,我们以test样式修改rpar/rseq函数:

test = do
    a <- rpar (fib 36)
    b <- rseq (fib 37)
    return (a,b)

我们对此计划进行了相同的实验。 (1)print r函数main:该程序为+RTS -N1+RTS -N2采用 3.283s 2.138s 标志分别; (2)print "hello"函数main+RTS -N1+RTS -N2的程序需要 1.956s 2.025s 分别。显然,在这种情况下,a中的btest都会被计算出来。

我在这个例子中有两个问题:

(1)何时在程序中实际计算出rparrseq个表达式?在评估(fib 36)时,似乎不会立即计算a <- rpar (fib 36)

(2)如果一台机器有足够的CPU核心并且我们在运行程序时指定了+RTS -N2标志,则ab的计算保证同时(或几乎同时)启动?

1 个答案:

答案 0 :(得分:3)

  1. 更大的问题是:何时在Haskell中计算事物?

    由于Haskell是一种懒惰的语言,我们只有在需要这种东西时才会计算出事物。特别是在您的第一个程序中,如果您从不要求revaluate只会将其计算到(,)构造函数),则fib调用永远不会被计算,并行性只是开销。

    在你的第二个程序rseq将要求包含计算的结果,因此无论你是否print,都会计算它。

  2. 使用+RTS -N2运行程序将使运行时使用2个Haskell执行上下文(HEC)。计算ab将添加到火花池中,并可供HEC计算。接下来会发生什么是GHC Runtime魔术,但如果计算不是太简单,你可以假设每个HEC都需要一个火花并计算它。

    有关RTS的更多阅读,请查看此论文集:https://ghc.haskell.org/trac/ghc/wiki/ReadingList#DataParallelHaskellandconcurrency(以及运行时间段),以及可能的Simon Marlow http://chimera.labs.oreilly.com/books/1230000000929