juh*_*nic 6 c mmap systems-programming
我有一个程序受 IO 限制,正在尝试加快速度。使用 mmap 似乎是一个好主意,但与仅使用一系列 fgets 调用相比,它实际上降低了性能。
我已经将演示压缩到了基本要素,对一个 800mb 的文件进行了测试,大约有 350 万行:
使用 fgets:
char buf[4096];
FILE * fp = fopen(argv[1], "r");
while(fgets(buf, 4096, fp) != 0) {
// do stuff
}
fclose(fp);
return 0;
Run Code Online (Sandbox Code Playgroud)
800mb 文件的运行时:
[juhani@xtest tests]$ time ./readfile /r/40/13479/14960
real 0m25.614s
user 0m0.192s
sys 0m0.124s
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
运行时变化很大,但永远不会比 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
Run Code Online (Sandbox Code Playgroud)
POSIX_MADV_SEQUENTIAL 只是对系统的一个提示,可能会被特定的 POSIX 实现完全忽略。
您的两种解决方案之间的区别在于,mmap需要将文件完全映射到虚拟地址空间,而fgetsIO 完全在内核空间中完成,只需将页面复制到不会更改的缓冲区中。
这也有更多的重叠可能性,因为 IO 是由某个内核线程完成的。
您也许可以mmap通过让一个(或多个)独立线程读取每个页面的第一个字节来提高实现的感知性能。这个(或这些)线程将有所有页面错误,并且当您的应用程序线程到达特定页面时,它已经被加载。
| 归档时间: |
|
| 查看次数: |
2950 次 |
| 最近记录: |