Haskell或F#高吞吐量二进制I / O.

时间:2010-12-31 17:39:53

标签: .net haskell f# io

这两种语言中二进制I / O库的性能有多好>我正在考虑重新编写一个丑陋(但非常快)的C ++代码,它使用标准的fread和fwrite函数处理大约5-10GB的二进制文件。对于F#和Haskell中的优化实现,我应该期待什么减速因子?

编辑: 这是计算零字节的C实现(在堆上分配的缓冲区)。

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

#define SIZE 32*1024
int main(int argc, char* argv[])
{
    FILE *fp;
    char *buf;
    long i = 0, s = 0, l = 0;
    fp = fopen(argv[1], "rb");
    if (!fp) {
        printf("Openning %s failed\n", argv[1]);
        return -1;
    }
    buf = (char *) malloc(SIZE);
    while (!feof(fp)) {
        l = fread(buf, 1, SIZE, fp);
        for (i = 0; i &lt l; ++i) {
            if (buf[i] == 0) {
                ++s;
            }
        }
    }
    printf("%d\n", s);
    fclose(fp);
    free(buf);
    return 0;
}

结果:


$ gcc -O3 -o ioc io.c
$ ghc --make -O3 -o iohs io.hs
Linking iohs ...
$ time ./ioc 2.bin
462741044

real    0m16.171s
user    0m11.755s
sys     0m4.413s
$ time ./iohs 2.bin
4757708340

real    0m16.879s
user    0m14.093s
sys     0m2.783s
$ ls -lh 2.bin
-rw-r--r-- 1  14G Jan  4 10:05 2.bin

3 个答案:

答案 0 :(得分:9)

Haskell使用 lazy 基于ByteString的IO,使用“二进制”解析器应该与执行相同作业的C代码在相同的数据类型上具有相同的性能。

要注意的关键包:

答案 1 :(得分:8)

考虑到这篇文章需要:

  • 的Haskell
  • 代码优化
  • 绩效基准

......可以肯定地说我已经超越了我的头脑。然而,当我进入我的头脑时,我总是学到一些东西,所以这里就是。

我通过Hoogle围绕Data.ByteString.Lazy.* Haskell模块进行了探索,并找到了length函数来测量惰性ByteString的长度。因此实施:

length :: ByteString -> Int64
length cs = foldlChunks (\n c -> n + fromIntegral (S.length c)) 0 cs

嗯。乔恩确实说过......“折叠文件中的是F#的主要原因......”(我的重点)。此length函数似乎也使用粗块折叠实现。所以看起来这个函数更像是与Jon的F#代码进行“苹果对苹果”的比较。

它在练习中有所作为吗?我将Jon的例子与以下内容进行了比较:

import System
import Data.List
import Data.ByteString.Lazy as B

main =
    getArgs
    >>= B.readFile . Data.List.head
    >>= print . B.length

Jon的Haskell示例在我的机器上获得1.2 GB文件: 10.5s

'矮胖'版本: 1.1s

Haskell代码的'chunky'版本几乎十倍更快。这表明它可能比Jon的优化F#代码快几倍。

修改

虽然我不一定完全同意Jon对我的例子的批评,但我想尽可能地使它成为可能的。因此,我已经描述了以下代码:

import System
import Data.List
import Data.ByteString.Lazy as B

main =
    getArgs
    >>= B.readFile . Data.List.head
    >>= print . B.count 0

此代码将目标文件的内容加载到ByteString中,然后“计数”每个0值字节的出现。除非我遗漏了某些内容,否则该程序必须加载并评估目标文件的每个字节。

上述程序的运行速度始终比Jon提交的最快的Haskell程序快4倍,复制在此作为参考(如果已更新):

import System
import Data.Int
import Data.List
import Data.ByteString.Lazy as B

main =
    getArgs
    >>= B.readFile . Data.List.head
    >>= print . B.foldl (\n c -> n + 1) (0 :: Data.Int.Int64)

答案 2 :(得分:2)

我在博客上发表了这篇文章here