我受到这篇名为“Only fast languages are interesting”的帖子的启发,以查看他在 Haskell 中提出的问题(从向量中求和数百万个数字)并与他的结果进行比较。
我是 Haskell 新手,所以我真的不知道如何正确计时或如何有效地做到这一点,我对这个问题的第一次尝试如下。请注意,我没有在向量中使用随机数,因为我不确定如何以一种好的方式去做。我也在打印东西以确保全面评估。
import System.TimeIt
import Data.Vector as V
vector :: IO (Vector Int)
vector = do
let vec = V.replicate 3000000 10
print $ V.length vec
return vec
sumit :: IO ()
sumit = do
vec <- vector
print $ V.sum vec
time = timeIt sumit
在 GHCI 中加载并运行
time
告诉我运行 300 万个号码大约需要 0.22 秒,运行 3000 万个号码需要 2.69 秒。与博客作者在 Lush 中 0.02 秒和 0.18 秒的结果相比,这要差得多,这让我相信这可以以更好的方式完成。
注意:以上代码需要 TimeIt 包才能运行。
cabal install timeit
会给你的。
最佳答案
首先,要意识到 GHCi 是一个解释器,它的设计并不是很快。要获得更有用的结果,您应该在启用优化的情况下编译代码。这可以产生巨大的影响。
此外,对于任何认真的 Haskell 代码基准测试,我建议使用 criterion .它使用各种统计技术来确保您获得可靠的测量结果。
我修改了您的代码以使用标准并删除了打印语句,这样我们就不会为 I/O 计时。
import Criterion.Main
import Data.Vector as V
vector :: IO (Vector Int)
vector = do
let vec = V.replicate 3000000 10
return vec
sumit :: IO Int
sumit = do
vec <- vector
return $ V.sum vec
main = defaultMain [bench "sumit" $ whnfIO sumit]
用
-O2
编译它,我在一个非常慢的上网本上得到了这个结果:$ ghc --make -O2 Sum.hs
$ ./Sum
warming up
estimating clock resolution...
mean is 56.55146 us (10001 iterations)
found 1136 outliers among 9999 samples (11.4%)
235 (2.4%) high mild
901 (9.0%) high severe
estimating cost of a clock call...
mean is 2.493841 us (38 iterations)
found 4 outliers among 38 samples (10.5%)
2 (5.3%) high mild
2 (5.3%) high severe
benchmarking sumit
collecting 100 samples, 8 iterations each, in estimated 6.180620 s
mean: 9.329556 ms, lb 9.222860 ms, ub 9.473564 ms, ci 0.950
std dev: 628.0294 us, lb 439.1394 us, ub 1.045119 ms, ci 0.950
所以我得到的平均时间刚刚超过 9 毫秒,标准偏差不到一毫秒。对于更大的测试用例,我得到大约 100 毫秒。
在使用
vector
时启用优化尤其重要。包,因为它大量使用流融合,在这种情况下,它能够完全消除数据结构,将您的程序变成一个高效、紧密的循环。通过使用
-fllvm
来试验新的基于 LLVM 的代码生成器可能也是值得的。选项。 It is apparently well-suited for numeric code .
关于optimization - 在 Haskell 中做有效的数值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8339644/