目前我正在追赶 Haskell,到目前为止我印象非常深刻。作为一个 super 简单的测试,我编写了一个程序来计算总和到十亿。为了避免创建列表,我写了一个应该是尾递归的函数
summation start upto
| upto == 0 = start
| otherwise = summation (start+upto) (upto-1)
main = print $ summation 0 1000000000
使用 -O2 运行它,我的机器上运行时间约为 20 秒,这让我感到惊讶,因为我认为编译器会更加优化。作为比较,我写了一个简单的 c++ 程序
#include <iostream>
int main(int argc, char *argv[]) {
long long result = 0;
int upto = 1000000000;
for (int i = 0; i < upto; i++) {
result += i;
}
std::cout << result << std::end;
return 0;
}
在没有优化的情况下使用 clang++ 编译运行时间约为 3 秒。所以我想知道为什么我的 Haskell 解决方案这么慢。有人有想法吗?
在 OSX 上:
铿锵++--版本:
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.2.0
Thread model: posix
ghc --版本:
The Glorious Glasgow Haskell Compilation System, version 7.10.3
最佳答案
添加类型签名将我的运行时间从 14.35 秒降低到 0.27。它现在比我机器上的 C++ 更快。当性能很重要时,不要依赖类型默认。 Ints 不适合在 Web 应用程序中对域进行建模,但如果你想要一个紧密的循环,它们就很棒。
module Main where
summation :: Int -> Int -> Int
summation start upto
| upto == 0 = start
| otherwise = summation (start+upto) (upto-1)
main = print $ summation 0 1000000000
[1 of 1] Compiling Main ( code/summation.hs, code/summation.o )
Linking bin/build ...
500000000500000000
14.35user 0.06system 0:14.41elapsed 100%CPU (0avgtext+0avgdata 3992maxresident)k
0inputs+0outputs (0major+300minor)pagefaults 0swaps
Linking bin/build ...
500000000500000000
0.27user 0.00system 0:00.28elapsed 98%CPU (0avgtext+0avgdata 3428maxresident)k
0inputs+0outputs (0major+171minor)pagefaults 0swaps
关于performance - 在 Haskell 中将所有数字从 1 加到 10 亿,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35019918/