【问题标题】:Haskell: How to improve performance of deep recursion and random number generationHaskell:如何提高深度递归和随机数生成的性能
【发布时间】:2015-12-30 17:03:29
【问题描述】:

感兴趣的问题是通过使其更快来增强以下递归深度为 100,000,000 的 Haskell 程序:

s :: Int32 -> Int32 -> IO Int32
s 0 acc = return $! acc
s n acc = do r <- randomRIO (0, maxBound :: Int32)
             s (n-1) $! (acc + r)

main = do z <- s 100000000 0
          putStrLn $ show z

这个程序在我的机器上大约需要 70 秒。 然而,一个对应的 C 程序只需要一秒钟:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>    

int main(){
    double startTime;
    double timeEllapsed;
    unsigned int sum;
    long long i;    

    startTime = clock();
    srand(time(NULL));    

    sum = 0;
    i = 0;
    for(i=0; i<100000000;i++){
      sum += rand();
    }    

    timeEllapsed = (clock() - startTime) / (CLOCKS_PER_SEC);    

    printf("sum = %u, time ellapsed = %lfs\n", sum, timeEllapsed);    

    return EXIT_SUCCESS;    
}

这种差异从何而来? Haskell标准库中随机数的实现是不是比较慢?还是应该使用与 randomRIO 不同的函数?还是与惰性评估有关? 你能优化 Haskell 程序上的任何内容并使其更快吗?

很明显,像 Haskell 和 C 这样的高级语言之间可能存在性能差异,但我没想到它会慢约 70 倍,所以我想知道原因。

【问题讨论】:

    标签: performance haskell recursion random


    【解决方案1】:

    是的,random 库非常慢。 randomRIO 在这种情况下并不理想,但使用其他功能 random 对速度没有太大帮助。有几种选择,Bryan O'Sullivan mwc-random 是最受欢迎的,但还有 Don Stewart 的 mersenne-random 和我自己的 pcg-random。另请注意,C 的rand 并不是一个特别好的随机数生成器。

    这是您的代码的类似 mwc-random 版本,在我的机器上运行 2.3 秒(ghc-7.10.2,带有 -O2 -fllvm

    import Control.Monad.ST
    import qualified System.Random.MWC as MWC
    import Data.Int
    
    s :: Int32 -> Int32 -> Int32
    s n s = runST $ do
      g <- MWC.create
    
      let go 0  !a = pure a
          go !i !a = do
            w <- MWC.uniformR (0, maxBound::Int32) g
            go (i-1) (a + w)
    
      go n s
    
    main :: IO ()
    main = print $ s' 100000000 0
    

    使用System.Random.PCG 的等效代码对我来说运行时间为 1 秒。并且在实验性的快速纯 pcg 代码上它可以在 0.28s 内运行:

    import System.Random.PCG.Fast.Pure
    
    s :: Int32
    s = go (100000000::Word64) 0xcafef00dd15ea5e5 0
      where
      go 0   _ a = a
      go !i !s a = go (i-1) s' (a + fromIntegral r)
        where P s' r = bounded 2147483647 s
    
    main = print s
    

    所以 Haskell 肯定能够快速生成随机数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-22
      • 2015-01-15
      • 1970-01-01
      • 1970-01-01
      • 2019-08-03
      • 2011-08-28
      相关资源
      最近更新 更多