什么是C++中高性能顺序文件I/O的最快方法?

Ada*_*erg 49 c++ performance file-io

假设以下内容...
输出:
文件打开...
数据"流式传输"到磁盘.内存中的数据位于一个大的连续缓冲区中.它直接从该缓冲区以原始格式写入磁盘.缓冲区的大小是可配置的,但在流的持续时间内是固定的.缓冲区一个接一个地写入文件.没有进行任何搜寻行动.
...文件已关闭.

输入:
从头到尾从磁盘读取一个大文件(按上面顺序写入).


是否有通用的指南来实现C++中最快的顺序文件I/O?

一些可能的考虑:

  • 选择最佳缓冲区大小的指南
  • 像boost :: asio这样的可移植库是否会过于抽象而无法暴露特定平台的复杂性,或者它们可以被认为是最优的?
  • 异步I/O总是优于同步吗?如果应用程序不受CPU限制怎么办?

我意识到这将有特定于平台的考虑因素.我欢迎一般准则以及特定平台的准则.
(我对Win x64最直接的兴趣,但我也对Solaris和Linux上的评论感兴趣)

qua*_*ark 32

是否有通用的指南来实现C++中最快的顺序文件I/O?

规则0:衡量.使用所有可用的性能分析工具并了解它们.这几乎是编程中的一条诫命,如果你没有测量它,你就不知道它有多快,而对于I/O来说,这更是如此.如果可能,请务必在实际工作条件下进行测试.对I/O系统没有竞争的过程可以过度优化,针对实际负载下不存在的条件进行微调.

  1. 使用映射内存而不是写入文件.这并不总是更快,但它允许以特定于操作系统但相对便携的方式优化I/O,避免不必要的复制,并利用操作系统对磁盘实际使用方式的了解.(如果使用包装器,则为"Portable",而不是特定于OS的API调用).

  2. 尽可能尝试并线性化您的输出.必须跳转内存以找到要写入的缓冲区在优化条件下会产生明显的效果,因为缓存行,分页和其他内存子系统问题将开始变得重要.如果你有很多缓冲区,请考虑支持scatter-gather I/O,它试图为你做线性化.

一些可能的考虑:

  • 选择最佳缓冲区大小的指南

初学者的页面大小,但准备从那里调整.

  • 像boost :: asio这样的可移植库是否会过于抽象而无法暴露特定平台的复杂性,或者它们可以被认为是最优的?

不要认为它是最佳的.这取决于库在您的平台上的运行程度,以及开发人员为实现这一目标所付出的努力.虽然说便携式I/O库可以非常快,因为大多数系统都存在快速抽象,并且通常可以提出涵盖许多基础的通用API.Boost.Asio是我最有限的知识,对于它所使用的特定平台进行了相当精细的调整:有一整套OS和OS变体特定的API用于快速异步I/O(例如 epoll,/ dev/epoll),kqueue,Windows重叠I/O),Asio将它们全部包装起来.

  • 异步I/O总是优于同步吗?如果应用程序不受CPU限制怎么办?

异步I/O在原始意义上并不比同步I/O快.异步I/O的作用是确保您的代码不会浪费时间等待I/O完成.它通常比不浪费时间的其他方法更快,即使用线程,因为它会在I/O准备就绪时而不是之前回调到代码中.没有错误启动或担心需要终止空闲线程.


Mar*_*utz 12

一般的建议是关闭大块缓冲和读/写(但不要太大,那么你将浪费太多时间等待整个I/O完成,否则你可能已经开始咀嚼第一兆字节了.使用这种算法找到最佳位置是微不足道的,只有一个旋钮:块大小).

除此之外,输入mmap()文件共享和只读是(如果不是最快的话)最有效的方式.madvise()如果你的平台有它,则调用它来告诉内核你将如何遍历文件,这样它就可以做readahead并在之后再次快速丢弃页面.

对于输出,如果您已有缓冲区,请考虑使用文件(也包括mmap())来支持它,因此您不必复制用户空间中的数据.

如果mmap()不是你喜欢的话,那就是fadvise(),对于非常棘手的,异步文件I/O.

(以上所有都是POSIX,Windows名称可能不同).


Mic*_*key 7

对于Windows,如果您选择使用特定于平台的Windows API调用,则需要确保在CreateFile()调用中使用FILE_FLAG_SEQUENTIAL_SCAN.这将优化I/O的缓存.就缓冲区大小而言,通常建议使用磁盘扇区大小的倍数的缓冲区大小.8K是一个很好的起点,从更大的角度来看,几乎没有什么可以获得的.

本文讨论Windows上的异步和同步之间的比较.

http://msdn.microsoft.com/en-us/library/aa365683(VS.85).aspx