mmap如何提高文件读取速度?
- 2024-10-18 09:00:00
- admin 原创
- 70
问题描述:
假设地址空间可以覆盖文件,在我看来,mmap 只是分配了一块与要读取的文件一样大的内存,并在其对应块之间创建了 1 对 1 的关系。但是,为什么这样做会加快文件读取速度?似乎为了真正获取文件的内容,您仍然必须转到磁盘并读取其中的所有字节。
与 malloc 分配相同大小的内存并手动将整个文件读入 malloc 区域相比,这有什么区别?
解决方案 1:
mmap
工作方式不同。它具有预见性并适应程序的访问模式。此外,还可以通过设置特定策略madvise
来进一步微调使用情况。
mmap
有关在需求分页环境中如何工作的更深入的讨论,请参阅我的回答:哪些段受写时复制的影响?因为它还讨论了使用mmap
mmap
是通过 et. al. 执行程序的命脉execve
。所以,你可以肯定它很快。顺便提一句,讽刺的是,实际上也malloc
使用匿名。mmap
但是,在这里的讨论中,特别要注意文件的“后备存储”(即分页磁盘)与mmap
执行malloc
和read(2)
对于mmap
,内存区域的后备存储就是文件本身。该区域将页面直接映射到内核的文件系统缓冲区页面 [它们已经统一了很长时间]。因此,不需要像 那样将内核文件系统缓冲区页面复制到应用程序页面 [浪费时间] read(2)
。
当您执行 时malloc/read
,您仍然拥有上述页面,但现在 malloc 区域在分页/交换磁盘上有一个后备存储。因此,页面缓冲区的数量是 的两倍mmap
。正如我所提到的,读取完成后必须将数据复制到该区域中。
此外,就性能而言,执行大量读取并不是最佳选择。建议的大小为每块 64 KB 左右 [取决于文件系统]。
当您执行大量读取时,程序在完成之前无法启动。如果文件的大小大于物理内存,系统将读入您的 malloc 区域,并将浪费地开始将较早的页面刷新到分页磁盘,为文件末尾附近的页面腾出空间,直到读入整个文件为止。
换句话说,在发生这种大型预读时,应用程序正在等待 [并且什么也不做]。对于 [例如] 60 GB 的文件,启动时间将非常明显。
如果您的文件确实足够大,您甚至会耗尽分页磁盘上的空间(即malloc
返回 NULL)。
对于 来说mmap
,不存在这样的问题。映射文件后,您可以立即开始使用它。它会根据需要直接从该区域的后备存储(再次强调,是文件系统中的文件)“故障转移”。而且,如果您有(比如说)1 TB 的文件,mmap
它可以很好地处理。
madvise(2)
此外,您还可以通过和posix_madvise(2)
逐页或任何页面范围(包括整个文件)控制映射策略。该madvise
系统调用相对较轻,因此可以大量使用它。这是一个提示,但不执行会延迟应用程序的 I/O。如果启动 I/O 以预读提示,则内核会将其作为后台活动完成。
您甚至可以告诉系统很快将需要某个页面 [并且系统将此作为预取该页面的提示] 或者您可以告诉系统不再需要该页面 [并且系统将释放页面缓冲内存]。
您可以对整个文件说“顺序访问”,这意味着系统将知道自动进行预读,以及释放不再需要的页面(即,如果您当前正在访问第 N 页,则系统将释放 Nk 之前的任何页面)
当您执行 时read(2)
,没有办法告诉系统不再需要给定的内核 FS 页缓冲区。它们会一直存在,直到物理 RAM 填满 [或超过给定的限制],这会给整个内存系统增加压力。
在实践中,使用read
,我发现在应用程序移动到文件的不同部分或完全不同的文件后,用于 FS 缓冲区的内存量仍然很高。事实上,我见过一个 I/O 密集型应用程序使用了如此多的缓冲区,以至于它导致不相关的 [空闲] 进程的页面被窃取并刷新到分页磁盘。当我停止 I/O 应用程序时,Firefox 需要几分钟才能重新分页并再次响应。
我对常规读取和 mmap 进行了一些广泛的基准测试。从中可以看出,mmap 可以提高某些应用程序的速度。
在这里看到我的答案:以最有效的方式逐行阅读特定于平台
在我这样做之前,我对 mmap 的好处持怀疑态度,但基准测试表明 mmap 是赢家。
另外,如果您正在进行read(2)
(为了速度)与fgets
,如果给定的行跨越读取缓冲区边界(即,缓冲区的最后 50 个字符具有 80 个字符行的前 50 个字节),那么您可能会因必须执行缓冲区移位而陷入困境。
请注意,在此链接页面的评论中,还有另一个指向 pastebin 的链接,指向我的基准测试程序的更高版本,其结果太大,无法发布在上述 SO 答案中,该答案对各种madvise
选项进行基准测试和比较
解决方案 2:
我对此感到很好奇,因此我尝试对大小为 1、2、4、8 等的文件的整个文件读取进行基准测试,一次使用mmap
(M),一次使用read
(R)(理论上使用 fstat 的大小进行一次调用,但如果该调用返回部分结果,它会重试)。在读取/映射之后,以不可优化的方式访问每个映射/读取页面的一个字节。
这是我的结果:
Size M(µs) R(µs)
1 9.5 4.2
2 10.8 4.5
4 8.4 3.8
8 8.6 3.8
16 7.3 4
32 7.8 3.5
64 8.3 3.9
128 9.2 4.6
256 8.6 4.7
512 10.6 5.1
1.0Ki 9.8 4.7
2.0Ki 10.1 5.4
4.0Ki 10.5 5.6
8.0Ki 10.4 6.9
16Ki 9.9 10
32Ki 14.4 12.8
64Ki 16.1 23.7
128Ki 28.1 41.1
256Ki 34.5 82.4
512Ki 57.9 154.6
1.0Mi 103.5 325.8
2.0Mi 188.5 919.8
4.0Mi 396.3 1963.2
8.0Mi 798.8 3885
16Mi 1611.4 7660.2
32Mi 3207.4 23040.2
64Mi 6712.1 84491.9
看起来read
速度大约是 的两倍,直到16Ki
。从那时起,mmap
开始大获全胜(对于文件,速度提高了1264MiB
倍)。
(在我的笔记本电脑上使用 Linux 3.19 进行测试,对同一个文件进行了 10^4 次重复读取。)
解决方案 3:
事实并非如此。具体来说,mmap() 不会在您调用它时将整个文件加载到内存中,以某种方式尝试加快访问速度。相反,它会映射文件,也就是说,在内存中创建文件的索引(我使用这个术语比较宽泛,请耐心听我说),这样当您尝试读取/写入该“键”时就会触发页面错误。因此,最终效果是您拥有一个简单的文件界面和一种文件内容的延迟加载。
我可以继续说下去,但其他人做得更好。例如,请参见此处。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件