小编典典

mmap() 与读取块

all

我正在开发一个程序,该程序将处理大小可能为 100GB
或更大的文件。这些文件包含可变长度记录集。我已经启动并运行了第一个实现,现在正在寻求提高性能,特别是在更有效地执行 I/O
方面,因为输入文件被扫描了很多次。

mmap()通过 C++
的库在块中使用与读取是否有经验法则fstream?我想做的是将大块从磁盘读取到缓冲区中,处理缓冲区中的完整记录,然后读取更多。

mmap()代码可能会变得非常混乱,因为’ mmapd
块需要位于页面大小的边界上(我的理解),并且记录可能会跨越页面边界。使用fstreams,我可以寻找记录的开头并再次开始阅读,因为我们不限于阅读位于页面大小边界上的块。

在没有实际编写完整实现的情况下,如何在这两个选项之间做出决定?任何经验法则(例如,mmap()快 2 倍)或简单测试?


阅读 67

收藏
2022-06-11

共1个答案

小编典典

我试图找到关于 Linux 上 mmap / 读取性能的最终决定,我在 Linux
内核邮件列表上发现了一篇不错的帖子(链接)。它是从 2000 年开始的,因此从那时起内核中的 IO
和虚拟内存有了很多改进,但它很好地解释了为什么mmap或者read可能更快或更慢的原因。

  • 调用的mmap开销大于read(就像epoll开销大于poll,开销大于read)。更改虚拟内存映射在某些处理器上是一项相当昂贵的操作,原因与在不同进程之间切换成本高昂的原因相同。
  • IO系统已经可以使用磁盘缓存,所以如果你读取一个文件,无论你使用什么方法,你都会命中或错过缓存。

然而,

  • 对于随机访问,内存映射通常更快,尤其是在您的访问模式稀疏且不可预测的情况下。
  • 内存映射允许您 继续 使用缓存中的页面,直到完成。这意味着如果您长时间大量使用文件,然后将其关闭并重新打开,页面仍然会被缓存。使用read,您的文件可能在很久以前就已从缓存中刷新。如果您使用文件并立即丢弃它,则不适用。(如果您尝试mlock页面只是为了将它们保存在缓存中,那么您就是在尝试智取磁盘缓存,而这种愚蠢的做法很少有助于系统性能)。
  • 直接读取文件非常简单快捷。

mmap/read 的讨论让我想起另外两个性能讨论:

  • 一些 Java 程序员震惊地发现非阻塞 I/O 通常比阻塞 I/O 慢,如果您知道非阻塞 I/O 需要进行更多的系统调用,这完全有道理。

  • 其他一些网络程序员惊讶地发现它epoll通常比.poll``epoll

结论:
如果您随机访问数据,将其保存很长时间,或者如果您知道可以与其他进程共享它(MAP_SHARED如果没有实际共享,则不是很有趣),请使用内存映射。如果您按顺序访问数据或在读取后将其丢弃,则可以正常读取文件。如果任何一种方法都可以让你的程序变得不那么复杂,
那就 这样做吧。对于许多现实世界的案例,如果不测试您的实际应用程序而不是基准测试,就无法确定一种方法会更快。

(对不起,这个问题被删除了,但我一直在寻找答案,这个问题一直出现在谷歌搜索结果的顶部。)

2022-06-11