use*_*460 11 .net io f# haskell
这两种语言中二进制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 < l; ++i) {
if (buf[i] == 0) {
++s;
}
}
}
printf("%d\n", s);
fclose(fp);
free(buf);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果:
$ 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
Run Code Online (Sandbox Code Playgroud)
考虑到这篇文章需要:
......可以肯定地说我已经超越了我的头脑.然而,当我进入我的脑海时,我总是学到一些东西,所以这里就是这样.
我Data.ByteString.Lazy.*通过Hoogle围绕Haskell模块进行了探索,并找到了用于测量惰性ByteString长度的长度函数.因此实施:
length :: ByteString -> Int64
length cs = foldlChunks (\n c -> n + fromIntegral (S.length c)) 0 cs
Run Code Online (Sandbox Code Playgroud)
嗯.Jon确实说过"...... 在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
Run Code Online (Sandbox Code Playgroud)
Jon的Haskell示例在我的机器上为1.2 GB文件:10.5s
'矮胖'版本:1.1s
Haskell代码的"矮胖"版本快了近十倍.这表明它可能比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
Run Code Online (Sandbox Code Playgroud)
此代码将目标文件的内容加载到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)
Run Code Online (Sandbox Code Playgroud)
我在这里写了关于这个的博客。