【问题标题】:Why is reading from a memory mapped file so fast?为什么从内存映射文件中读取速度如此之快?
【发布时间】:2014-12-14 21:03:22
【问题描述】:

我在内存映射 i/o 方面没有太多经验,但在第一次使用它们之后,我对它们的速度感到震惊。在我的性能测试中,我发现从内存映射文件读取比通过常规 c++ stdio 读取快 30 倍。

我的测试数据是一个 3GB 的二进制文件,它包含 20 个大型双精度浮点数组。我的测试程序的结构方式是调用外部模块的读取方法,该方法在后台使用内存映射 i/o。每次我调用 read 方法时,这个外部模块都会返回一个指针和指针指向的数据的大小。从这个方法返回后,我调用 memcpy 将返回的缓冲区的内容复制到另一个数组中。由于我正在执行 memcpy 以从内存映射文件中复制数据,因此我预计内存映射读取不会比普通 stdio 快得多,但令我惊讶的是它快了 30 倍。

为什么从内存映射文件读取速度如此之快?

PS:我使用的是 Windows 机器。我对我的 i/o 速度进行了基准测试,我的机器的最大磁盘传输速率约为 90 MiB/s

【问题讨论】:

  • 你可以找到答案here
  • @SteveLorimer:我在发布之前确实阅读了该页面。根据我从该线程收集的信息,如果数据尚未在内存中,则操作系统必须从磁盘中获取数据。我在测试中看到的是没有对应于 3GB 数据传输的磁盘 i/o,我只看到传输量为 2630 字节。但是,当我检查 memcpy-ed 数组的内容时,它们与预期的数据字节匹配。
  • 标准基准风险。 Look here.
  • @HansPassant:谢谢你的链接。在我的示例运行之间清空 Windows 文件缓存后,我发现我的超快内存映射 i/o 比以前慢了 30 倍!
  • @DigitalEye 在这种情况下,您仍然认为下面的答案是正确的解释吗?

标签: c++ windows memory-mapped-files


【解决方案1】:

用于 IO 的 OS 内核例程,如读取或写入调用,仍然只是函数。这些函数被写入将数据复制到/从用户空间缓冲区复制到内核空间结构,然后复制到设备。当您考虑有一个用户缓冲区、一个 IO 库缓冲区(例如 stdio buf)、一个内核缓冲区,然后是一个文件时,数据可能会通过 3 个副本在您的程序和磁盘之间获取。 IO 例程还必须是健壮的,最后,系统调用本身会施加延迟(捕获到内核、上下文切换、再次唤醒进程)。

当您对文件进行内存映射时,您会跳过其中的大部分内容,从而消除缓冲区副本。通过有效地将文件视为一个大型虚拟数组,您可以启用随机访问而无需通过系统调用开销,因此您可以降低每个 IO 的延迟,并且如果原始代码效率低下(许多小的随机 IO 调用),那么开销甚至会减少更彻底。

虚拟内存的抽象,多处理操作系统是有代价的,就是这样。

但是,在某些情况下,您可以通过禁用缓冲来改善 IO,以防您知道缓冲会损害性能,例如大量连续写入,但除此之外,如果不消除内存映射 IO 的性能,您确实无法提高完全操作系统。

【讨论】:

  • 所以公平地说,在我的情况下,数据直接从磁盘到我的阵列,即一个副本,而不是您描述的三个:磁盘到内核缓冲区,内核缓冲区到i/o 缓冲区,最后是我程序内存的 i/o 缓冲区?
  • 是的。同样,如果内核将您的文件映射到一组页面,并且这些页面不存在(尚未驻留),内核将页面错误并直接读取这些页面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-07
  • 2015-05-20
  • 1970-01-01
  • 1970-01-01
  • 2012-10-11
  • 1970-01-01
相关资源
最近更新 更多