haskell - Haskell 中的基本 I/O 性能

标签 haskell ghc

另一个微基准测试:为什么这个“循环”(用 ghc -O2 -fllvm 编译,7.4.1,Linux 64bit 3.2 内核,重定向到 /dev/null )

mapM_ print [1..100000000]

比普通的简单 for-cycle 慢约 5 倍 Cwrite(2)非缓冲系统调用?我正在尝试收集 Haskell 问题。

即使这种缓慢的 C 解决方案也比 Haskell 快得多
int i;
char buf[16];
for (i=0; i<=100000000; i++) {
    sprintf(buf, "%d\n", i);
    write(1, buf, strlen(buf));
}

最佳答案

好的,我的盒子上有 C 代码,根据 gcc -O3 编译运行大约需要 21.5 秒,原始 Haskell 代码大约需要 56 秒。所以不是 5 的因数,略高于 2.5。

第一个重要的区别是

mapM_ print [1..100000000]

用途 Integer s,这有点慢,因为它涉及预先检查,然后使用盒装 Int s,而 Show Int 的实例对未装箱的 Int# 是否进行转换工作s。

添加类型签名,以便 Haskell 代码适用于 Int
mapM_ print [1 :: Int .. 100000000]

将时间缩短到 47 秒,比 C 代码花费的时间多一倍。

现在,另一个很大的区别是 show产生 Char 的链表并且不只是填充连续的字节缓冲区。那也比较慢。

然后是Char的链表s 用于填充字节缓冲区,然后将其写入 stdout处理。

所以,Haskell 代码比 C 代码做更多、更复杂的事情,因此它需要更长的时间也就不足为奇了。

诚然,希望有一种简单的方法来更直接地(因此更快)输出这些东西。但是,处理它的正确方法是使用更合适的算法(也适用于 C)。一个简单的改变
putStr . unlines $ map show [0 :: Int .. 100000000]

花费的时间几乎减少了一半,如果想要真的很快,可以使用更快的 ByteString I/O 并有效地构建输出,如 applicative's answer 中所示.

关于haskell - Haskell 中的基本 I/O 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13334074/

相关文章:

Haskell:使用 UNPACK Pragma 的 GADT

list - 一口气解压?

windows - Haskell 中 System.Info "os"函数的可能值是多少?

optimization - 解包严格字段如何与多态性结合在一起?

scala - Haskell : ".... there is no single type that contains both 2 and ' b'. 的温和介绍“我不能制作这样的类型吗?

haskell - 了解 `GHC.TypeLits`

haskell - 内部模块的跨模块内联

haskell - Haskell 中的索引仿函数到底是什么,它的用途是什么?

haskell - Agda 类型检查和交换性/+ 的关联性

haskell - 在 Haskell 中解决 Google Code Jam 的 "Minimum Scalar Product"