首页 / 知识
关于c ++:mmap()与阅读块
2023-04-14 08:05:00

mmap() vs. reading blocks我正在开发一个程序,该程序将处理大小可能为100GB或更大的文件。这些文件包含可变长度记录集。我已经启动并运行了第一个实现,现在正寻求提高性能,尤其是由于输入文件被扫描了多次,因此更有效地执行I / O。
使用
我如何在这两个选项之间做出决定,而无需先实际编写完整的实现?任何经验法则(例如
我试图找到关于mmap /在Linux上读取性能的最终结论,并且在Linux内核邮件列表中遇到了一篇不错的文章(链接)。从2000年开始,因此从那时起内核中的IO和虚拟内存有了许多改进,但是很好地解释了
然而,
mmap / read的讨论使我想起了另外两个性能讨论:
结论:如果您随机访问数据,将其保留很长时间,或者您知道可以与其他进程共享(如果没有实际共享,则 (对这个问题的回答很抱歉,但我一直在寻找答案,并且这个问题一直出现在Google搜索结果的顶部。) 主要的性能成本将是磁盘I / O。" mmap()"当然比istream快,但是这种差异可能并不明显,因为磁盘I / O将主导您的运行时。 我尝试了Ben Collins的代码片段(请参见上/下),以测试他对" mmap()更快"的断言,但没有发现可测量的差异。看到我对他的回答的评论。 我当然不建议单独依次映射每个记录,除非您的"记录"很大-这将非常慢,需要为每个记录进行2次系统调用,并且有可能使页面从磁盘内存缓存中丢失。 。 在您的情况下,我认为mmap(),istream和低级open()/ read()调用几乎都是相同的。在以下情况下,我建议使用mmap(): (顺便说一句-我爱mmap()/ MapViewOfFile())。 mmap更快。您可以编写一个简单的基准来向自己证明:
与:
显然,我遗漏了一些细节(例如,如果文件不是 如果可以的话,您可以尝试将数据分解为多个文件,这些文件可以整体而不是部分进行mmap()编辑(更简单)。 几个月前,我对boost_iostreams的滑动窗口mmap()-ed流类进行了半熟的实现,但是没人关心,我开始忙于其他工作。最不幸的是,几周前我删除了一个旧的未完成项目的档案,这是受害者之一:-( 更新:我还应该添加一个警告,即该基准在Windows中看起来会完全不同,因为Microsoft实现了一个漂亮的文件缓存,该缓存首先执行了mmap的大部分操作。即,对于频繁访问的文件,您可以执行std :: ifstream.read(),它的速度与mmap一样快,因为文件缓存已经为您完成了内存映射,并且是透明的。
最终更新:您好,人们:在OS和标准库以及磁盘和内存层次结构的许多不同平台组合中,我不能肯定地说系统调用
编辑以清理答案列表:
当然-我当时正在为Git(如果愿意的话,为libgit ++)编写一个C ++库,并且遇到了与此类似的问题:我需要能够打开大型文件(大型文件),而性能却不高(与
这里已经有很多很好的答案,涵盖了很多要点,所以我只添加一些我没有直接在上面解决的问题。也就是说,此答案不应被视为全面的利弊,而应视为此处其他答案的附录。 好。 mmap看起来像魔术
以文件已经被完全缓存1为基线2的情况来看, 好。 如果文件已经在高速缓存中,则似乎无法克服:您只是直接访问内核页面高速缓存作为内存,并且它的速度不能超过此速度。 好。 好吧,可以。 好。 mmap实际上不是魔术,因为... mmap仍然可以按页面工作
好。
例如,一个典型的实现只是整个文件的 好。 mmap严重依赖TLB性能
现在,您可以将 好。
最后,即使在用户空间中访问,这种映射也不是完全免费的(与不是源自基于文件的 好。 现在,这些TLB缺失的实际成本在很大程度上至少取决于硬件的以下方面:(a)您拥有多少个4K TLB实体以及其余的转换缓存如何工作(b)硬件预取处理得如何好使用TLB-例如,预取能否触发页面浏览? (c)分页浏览硬件的速度和并行度。在现代高端x86 Intel处理器上,页面浏览硬件通常非常强大:至少有2个并行页面浏览器,页面浏览可以与连续执行同时发生,并且硬件预取可以触发页面浏览。因此,TLB对流式读取负载的影响非常小-而且无论页面大小如何,这种负载通常都将以类似的方式执行。但是,其他硬件通常更差! 好。 read()避免了这些陷阱
好。 好。
另一方面,它可以避免上述大部分费用-您无需将2500万个4K页面映射到用户空间。通常,您可以在用户空间中 好。 因此,基本上,您可以通过以下比较来确定对大文件的单次读取速度更快: 好。
好。 在许多系统上,它们实际上是近似平衡的。请注意,每个扩展都具有完全不同的硬件和OS堆栈属性。 好。
特别是在以下情况下, 好。 好。
...在以下情况下 好。 好。 上述硬件因素在不同平台之间(甚至在同一系列内(例如在x86代之内,尤其是细分市场中))差异很大,并且在不同体系结构(例如ARM,x86和PPC)之间也存在很大差异。 好。 操作系统因素也在不断变化,双方的各种改进都导致一种方法或另一种方法的相对速度大幅提高。最近的列表包括: 好。 好。 幽灵和崩溃后更新 Spectre和Meltdown漏洞的缓解措施大大增加了系统调用的成本。在我测量的系统上,"不执行任何操作"系统调用(除了该调用完成的任何实际工作之外,它是系统调用的纯开销的估计)的成本大约为100 ns现代Linux系统大约需要700 ns。此外,根据您的系统,由于需要重新加载TLB条目,专门用于Meltdown的页表隔离修复程序可能会具有其他下游影响,除了直接的系统调用成本之外。 好。
与基于 好。
另一方面,使用 好。
1这种或多或少的情况还包括文件没有被完全缓存到开始的情况,但预读操作系统足以使文件看起来像这样(例如,页面通常在您存储时被缓存)。想要它)。但是,这是一个微妙的问题,因为 好。
2 ...因为如果不缓存文件,那么您的行为将完全由IO问题决定,包括您对底层硬件的访问模式有多同情-您应尽一切努力确保此类访问具有同情心 可能的,例如 通过使用
3例如,您可以通过依次在较小尺寸(例如100 MB)的窗口中依次
4实际上,事实证明 好。 抱歉,本·科林斯(Ben Collins)丢失了滑动窗口的mmap源代码。在Boost中拥有它真是太好了。 是的,映射文件要快得多。本质上,您是在使用OS虚拟内存子系统来将内存与磁盘关联,反之亦然。这样考虑:如果OS内核开发人员可以使其更快,他们就会这样做。因为这样做可以使几乎所有事情变得更快:数据库,启动时间,程序加载时间等等。 滑动窗口方法实际上并不难,因为可以一次映射多个连续页面。因此,记录的大小无关紧要,只要任何单个记录中的最大记录可以放入内存即可。重要的是管理簿记。 如果记录不是从getpagesize()边界开始的,则映射必须从前一页开始。映射区域的长度从记录的第一个字节(必要时向下舍入到getpagesize()的最接近倍数)到记录的最后一个字节(舍入到getpagesize()的最接近倍数)。处理完记录后,可以取消对其的映射(),然后移至下一条。 在Windows下,也可以使用CreateFileMapping()和MapViewOfFile()(以及GetSystemInfo()来获取SYSTEM_INFO.dwAllocationGranularity ---而不是SYSTEM_INFO.dwPageSize),在Windows上也可以正常工作。 mmap应该更快,但我不知道多少。这在很大程度上取决于您的代码。如果使用mmap,则最好一次映射整个文件,这将使您的工作变得更加轻松。一个潜在的问题是,如果您的文件大于4GB(或者实际上限制较低,通常为2GB),则需要64位体系结构。因此,如果您使用的是32环境,则可能不想使用它。 话虽如此,可能会有一条更好的途径来提高性能。您说输入文件被扫描了很多次,如果您可以一次性读取它,然后完成处理,则可能会更快。 我同意mmap的文件I / O会更快,但是在对代码进行基准测试时,是否应该对反例进行一些优化? 本·科林斯写道:
我建议也尝试:
除此之外,您还可以尝试使缓冲区大小与虚拟内存的一页大小相同,以防万一0x1000不是您计算机上虚拟内存的一页大小...恕我直言,仍然有文件I / O胜,但这应该使事情变得更紧密。 也许您应该对文件进行预处理,所以每个记录都在一个单独的文件中(或者至少每个文件都可以映射)。 还可以在移至下一条记录之前对每条记录执行所有处理步骤吗?也许这样可以避免一些IO开销?
我记得几年前将包含树结构的巨大文件映射到内存中。与普通的反序列化相比,它的速度令我惊讶,后者需要大量的内存工作,例如分配树节点和设置指针。 在我看来,使用mmap()"只是"使开发人员不必编写自己的缓存代码。在一个简单的"一次读取文件一次"的情况下,这并不困难(尽管mlbrock指出您仍将内存副本保存到进程空间中),但是如果要在文件中来回移动或跳过诸如此类,我相信内核开发人员在实现缓存方面可能做得比我更好。 我认为mmap的最大优点是可以异步读取:
问题是我找不到正确的MAP_FLAGS来提示应该从文件asap同步此内存。 这听起来像是多线程的好用例……我想您可以很容易地将一个线程设置为读取数据,而其他线程则对其进行处理。这可能是显着提高感知性能的一种方式。只是一个想法。 |
最新内容
相关内容
linux输入过的命令?
linux输入过的命令?,系统,地址,数字,命令,工具,工作,环境,界面,历史,指令,linux系统查看自己在linux上使用过的前10次命令1、首先打开Linux直linux命令添加文件?
linux命令添加文件?,工作,简介,数据,系统,文件,命令,操作,文件名,内容,终端,linux哪些指令可以创建文件终端下键入:touch加文件名,这样就创建了linux退出启动命令行?
linux退出启动命令行?,系统,状态,档案,平台,命令,环境,模式,终端,程序,编辑,linux如何退出命令操作界面1、在Linux系统中,按下Ctrl+Alt+F2可以linux进程运行命令?
linux进程运行命令?,系统,工作,状态,地址,信息,进程,基础,命令,管理,软件,linux常用命令有哪些1、linux系统常用操作命令linux系统常用操作命linux文件输入命令?
linux文件输入命令?,工作,系统,地址,信息,工具,位置,命令,设备,发行,首开,linux中使用vi指令后怎么输入?1、[Ctrl]+[f]:屏幕向下移动一页,相当于文件备份命令linux?
文件备份命令linux?,网站,系统,设备,文件,软件,网络,工具,环境,数据,地址,linux怎么备份数据库(linux如何备份mysql数据库)1、将MYSQL数据放在linux遍历文件命令?
linux遍历文件命令?,系统,数据,工具,文件,平台,信息,百度,位置,时间,适当,linux遍历文件每一行会变化吗1、自我实现 首先需要将所有的文件读取linux命令查看小文件?
linux命令查看小文件?,系统,档案,文件夹,标准,软件,单位,文件,命令,大小,内容,linux下怎么查看文件夹中各个文件的大小df可以查看一级文件夹大linux文件中剪切命令?
linux文件中剪切命令?,位置,系统,工作,命令,发行,连续,标准,终端,文件,目录,linux怎么粘贴粘贴与复制快捷键 Shift + Ctrl + c:复制。Shift + Clinux命令行不能输入?
linux命令行不能输入?,工作,系统,电脑,服务,命令,名字,首次,百度,管理,第一,linux中的命令如何输入linux常用命令:pwd命令该命令的英文解释为prlinux存储文件命令?
linux存储文件命令?,系统,地址,工作,命令,软件,电脑,标准,底部,信息,文件,linux系统常用操作命令1、linux常用命令有pwd命令、cd命令、ls命令linux保存命令文件?
linux保存命令文件?,系统,状态,命令,文件,第一,管理,电脑,模式,编辑,终端,linux下vi命令编辑器怎样编辑及保存退出?先按ESC进入Command模式,然