mmap()与读取数据块的区别

243

我正在开发一个程序,将要处理可能大小为100GB或更大的文件。这些文件包含了长度可变的多组记录。我已经完成了第一个实现,并且现在致力于提高性能,特别是在更有效地进行I/O操作方面,因为输入文件需要被扫描多次。

有没有一些使用mmap()和C++的fstream库读取块的经验法则?我的想法是从磁盘中读取大块到缓冲区,从缓冲区处理完整的记录,然后再读取更多。

mmap()代码可能会变得非常混乱,因为mmap的块需要位于页面大小的边界上(据我所知),而记录可能潜在地跨越页面边界。通过使用fstreams,我可以直接寻找记录的起点并开始读取,因为我们不受限于只读取位于页面大小的边界上的块。

在实际编写一个完整实现之前,如何在这两个选项之间做出选择?是否有什么经验法则(例如,mmap()速度是2倍)或简单测试?


4
这是一篇有趣的文章:https://medium.com/@sasha_f/why-mmap-is-faster-than-system-calls-24718e75ab37 在实验中,使用mmap()比使用系统调用(例如read())快2-6倍。 - mplattner
13个回答

2

这听起来是多线程的一个很好的应用场景...我认为你可以很容易地设置一个线程来读取数据,而另一个或其他线程则处理它。这可能是一种显著提高感知性能的方法。这只是一个想法。


是的。我一直在考虑这个问题,可能会在以后的版本中尝试一下。我唯一的顾虑是处理时间远远短于I/O延迟,因此可能没有太多好处。 - jbl

1

我认为mmap最伟大的地方就是它具有异步读取的潜力:

    addr1 = NULL;
    while( size_left > 0 ) {
        r = min(MMAP_SIZE, size_left);
        addr2 = mmap(NULL, r,
            PROT_READ, MAP_FLAGS,
            0, pos);
        if (addr1 != NULL)
        {
            /* process mmap from prev cycle */
            feed_data(ctx, addr1, MMAP_SIZE);
            munmap(addr1, MMAP_SIZE);
        }
        addr1 = addr2;
        size_left -= r;
        pos += r;
    }
    feed_data(ctx, addr1, r);
    munmap(addr1, r);

问题是我找不到正确的MAP_FLAGS来提示这个内存应该尽快从文件同步。 我希望MAP_POPULATE能为mmap提供正确的提示(即在调用返回之前不会尝试加载所有内容,而是异步地使用feed_data完成)。至少使用此标志可以获得更好的结果,即使手册说明自2.6.23以来没有MAP_PRIVATE也无效。

2
你想使用带有WILLNEED标志的posix_madvise来进行懒惰提示以预填充。 - ShadowRanger
@ShadowRanger,听起来很合理。不过我会更新man页面,明确说明posix_madvise是异步调用。对于那些想要等待整个内存区域在没有页面故障的情况下变得可用的人,引用mlock也是一个好主意。 - ony

0
我进行了一项测试,比较了25年前(仅限Windows)和今天2023年(在Windows 11 AMD Ryzen Threadripper 3970X和搭载M1-Max芯片的macOS上,均配备快速SSD NVMe)的“映射 vs 读取”访问速度。在所有情况下,我只对顺序访问感兴趣,这是我C++基准测试(操作系统API调用)的重点。
在每次测试中,我非常注意彻底清除系统缓存以确保准确的结果。在Mac上,我使用了“sudo purge”命令,在Windows上,我使用了RAMMap64.exe应用程序,并选择“Empty Standby List”选项在运行每个基准测试之前。
我的研究结果始终如一:利用文件内存映射的速度明显较慢,令我感到失望。在Windows上慢了5倍,在macOS上慢了7倍。 此外,在macOS上,读取速度比Windows快4倍,内存映射速度快3倍。对我来说,这很不幸,因为我大部分时间都在使用Windows。
有趣的是,当我不清除系统缓存并重新运行基准测试时,映射和读取之间的差距大大减小,尽管读取仍然比映射快大约30%。
总之,非常重要的是进行准确反映您选择操作系统的特定需求的基准测试。此外,在每次测试之前不要忽视清除系统缓存的重要性。根据这些基准测试,自行得出适合您需求的最佳方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接