一尘不染

为什么mmap()比顺序IO快?

linux

我听说(在互联网上的某处阅读)mmap()比顺序IO快。它是否正确?如果是,那为什么会更快?

  • mmap() 没有按顺序阅读。
  • mmap()已经从磁盘读取本身一样read()
  • 映射区域不是顺序的-因此没有DMA(?)。

那么mmap()实际上应该比read()从文件慢吗?我上面的哪些假设是错误的?


阅读 814

收藏
2020-06-03

共1个答案

一尘不染

我听说(在互联网上的某处阅读)mmap()比顺序IO更快。它是否正确?如果是,那为什么会更快?

可能是-有优点和缺点,如下所列。 当您真的有理由要关心时,请始终对它们进行基准测试

除了实际的IO效率外,应用程序代码在需要执行I / O以及进行数据处理/生成时的跟踪方式也会产生影响,有时会极大地影响性能。

1)mmap()没有顺序读取。2)mmap()必须从磁盘本身读取,就像read()一样。3)映射区域不是顺序的-因此没有DMA(?)。

那么mmap()实际上应该比文件中的read()慢吗?我上面的哪些假设是错误的?

1)错误…
mmap()分配与文件内容相对应的虚拟地址空间区域…每当访问该地址空间中的页面时,都会发现物理RAM支持该虚拟地址,并且相应的磁盘内容也被错误放入该RAM
。因此,从磁盘读取的顺序与访问顺序相匹配。这是一种“惰性” I /
O机制。例如,如果您需要索引到要从磁盘读取的巨大哈希表,则mmap对文件进行访问并开始进行访问意味着磁盘I /
O不会顺序执行,因此可能需要更长的时间才能将整个文件读入内存,但是在这种情况下,查找成功并且可以进行相关工作,并且如果从未真正需要文件的某些部分,则不会读取它们(允许使用磁盘和内存页面的粒度,即使使用内存映射,许多操作系统也可以让您指定一些有关计划的性能增强/内存效率提示访问模式,以便他们知道您不太可能返回时可以提前读取或更积极地释放内存)。

2)绝对正确

3)“映射区域不是顺序的”是模糊的。内存映射区域在虚拟地址空间中是“连续的”(顺序的)。上面我们已经讨论了磁盘I /
O是顺序的。或者,您是否在想其他事情?无论如何,当页面出现故障时,确实可以使用DMA来传输它们。

此外,还有其他原因导致内存映射可能会超出常规I / O:

  • 复制较少:
    • 通常,操作系统和库级别的例程在到达应用程序指定的缓冲区之前将数据通过一个或多个缓冲区,然后应用程序动态分配存储,然后从I / O缓冲区复制到该存储,以便在文件读取完成后数据可以使用
    • 内存映射允许(但不强制)就地使用(您可以只记录一个指针,也可以记录长度)
    • 继续访问就地数据的风险后来增加了交换:文件/内存映射可能比解析它的数据结构更冗长,因此其中数据的访问模式可能会在更多内存页中出现更多故障延迟
  • 内存映射可以让应用程序将整个文件内容视为可访问的,而不用担心何时读取另一个已满的缓冲区,从而简化了应用程序的解析工作。
  • 该应用程序可以更好地利用操作系统在任何单个时间点的物理RAM中的页面数,从而与该应用程序有效共享直接访问磁盘缓存
  • 以及下面的祝福,“使用内存映射通常可以减少系统调用”
  • 如果多个进程正在访问同一个文件,则它们应该能够共享物理后备页面

这也是为什么mmap速度可能较慢的原因-请在此处阅读Linus
Torvald的帖子,其中写道mmap

…页面桌面游戏以及故障(甚至只是TLB丢失)开销远远超过以一种不错的流方式复制页面的成本…

他的一篇文章中

  • 相当显着的安装和拆卸成本。我的意思是 引人注目
    。就像跟随页面表以完全取消映射所有操作一样。这是维护所有映射列表的簿记。取消映射后需要TLB刷新。

  • 页面错误很昂贵。这就是映射的填充方式,而且相当慢。

FWIW,这是我上一次出现这种情况时fread,在具有170GB文件的64位Linux上,内存映射输入比将二进制数据库记录读取到专有数据库中的速度快80%。

2020-06-03