加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 为什么用mmap顺序读取一个大文件,而madvise顺序比fgets慢?

发布时间:2020-12-16 09:34:50 所属栏目:百科 来源:网络整理
导读:概观 我有一个由IO显着限制的程序,我正试图加快它. 使用mmap似乎是一个好主意,但它实际上相对于仅使用一系列fgets调用会降低性能. 一些演示代码 我已经将演示文稿简化为必需品,测试了一个大约350万行的800mb文件: 随着fgets: char buf[4096];FILE * fp = f
概观

我有一个由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,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

其他说明

>观看流程在顶部运行,memmapped版本在此过程中产生了几千个页面错误.
> fgets版本的CPU和内存使用率都非常低.

问题

>为什么会这样?是不是因为fopen / fgets实现的缓冲文件访问比使用madvise POSIX_MADV_SEQUENTIAL进行mmap的积极预取更好?
>是否存在可能使其更快的替代方法(除了实时压缩/解压缩以将IO负载转移到处理器)?在同一个文件上查看’wc -l’的运行时,我猜这可能不是这种情况.

解决方法

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

两种解决方案之间的区别在于mmap要求将文件映射到虚拟地址空间,而fgets在内核空间中完全完成IO,只是将页面复制到不会更改的缓冲区中.

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

您可以通过让一个(或多个)独立线程读取每个页面的第一个字节来提高mmap实现的感知性能.然后,这个(或这些)线程将具有所有页面错误以及应用程序线程将在已经加载的特定页面上的时间.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读