gpt4 book ai didi

c - 为什么使用 mmap 和 madvise 顺序逐行读取大文件比 fgets 慢?

转载 作者:太空狗 更新时间:2023-10-29 15:59:43 28 4
gpt4 key购买 nike

概览

我有一个受 IO 显着限制的程序,我正试图加快它的速度。使用 mmap 似乎是个好主意,但相对于仅使用一系列 fgets 调用,它实际上会降低性能。

一些演示代码

我已经将演示压缩到只包含基本部分,针对一个包含大约 350 万行的 800mb 文件进行测试:

使用 fgets:

char buf[4096];
FILE * fp = fopen(argv[1], "r");

while(fgets(buf, 4096, fp) != 0) {
// do stuff
}
fclose(fp);
return 0;

800mb 文件的运行时间:

[juhani@xtest tests]$ time ./readfile /r/40/13479/14960 

real 0m25.614s
user 0m0.192s
sys 0m0.124s

mmap 版本:

struct stat finfo;
int fh, len;
char * mem;
char * row, *end;
if(stat(argv[1], &finfo) == -1) return 0;
if((fh = open(argv[1], O_RDONLY)) == -1) return 0;

mem = (char*)mmap(NULL, finfo.st_size, PROT_READ, MAP_SHARED, fh, 0);
if(mem == (char*)-1) return 0;
madvise(mem, finfo.st_size, POSIX_MADV_SEQUENTIAL);
row = mem;
while((end = strchr(row, '\n')) != 0) {
// do stuff
row = end + 1;
}
munmap(mem, finfo.st_size);
close(fh);

运行时变化很大,但绝不会比 fgets 快:

[juhani@xtest tests]$ time ./readfile_map /r/40/13479/14960

real 0m28.891s
user 0m0.252s
sys 0m0.732s
[juhani@xtest tests]$ time ./readfile_map /r/40/13479/14960

real 0m42.605s
user 0m0.144s
sys 0m0.472s

其他说明

  • 观察在 top 中运行的进程,memmapped 版本在此过程中产生了几千个页面错误。
  • fgets 版本的 CPU 和内存使用率都非常低。

问题

  • 为什么会这样?仅仅是因为 fopen/fgets 实现的缓冲文件访问比使用 madvise POSIX_MADV_SEQUENTIAL 的 mmap 的积极预取更好吗?
  • 是否有其他方法可以加快速度(除了即时压缩/解压缩以将 IO 负载转移到处理器之外)?查看同一文件上“wc -l”的运行时,我猜情况可能并非如此。

最佳答案

POSIX_MADV_SEQUENTIAL 只是对系统的提示,可能会被特定的 POSIX 实现完全忽略。

你的两个解决方案之间的区别在于 mmap 需要将文件完整地映射到虚拟地址空间,而 fgets 的 IO 完全在内核空间中完成,并且只是将页面复制到一个不变的缓冲区中。

这也有更多的重叠可能性,因为 IO 是由某个内核线程完成的。

您或许可以通过让一个(或多个)独立线程读取每个页面的第一个字节来提高 mmap 实现的感知性能。然后,这个(或这些)线程将出现所有页面错误,并且当您的应用程序线程到达某个特定页面时,该页面已经被加载。

关于c - 为什么使用 mmap 和 madvise 顺序逐行读取大文件比 fgets 慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6055861/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com