【问题标题】:How to maximize SSD I/O in C++?如何在 C++ 中最大化 SSD I/O?
【发布时间】:2019-12-16 03:23:39
【问题描述】:

我编写了一个程序来将二维数组读写到 NVME SSD(三星 970EVO plus)中。

我将程序设计为像 as 一样读取 N*M

#pragma omp parallel for
for(int i=0;i<N;i++)
  fstream.read(...) // read M bytes

但是,此代码显示的性能(KB/s)低于 SSD 规格(

我认为如果大小 M 大于块大小(可能是 4KB)并且是 2 的倍数,那么该代码将显示 GB/s 性能。

然而,事实并非如此。我想我错过了什么。

是否有一些 c++ 代码可以最大限度地提高 SSD 上的 I/O 性能?

【问题讨论】:

  • GB/s 规格有点无关紧要,因为它受到所有中间硬件(例如主板,如果使用板载 SATA)的吞吐量以及您的 PC 实际消耗读取数据的速度的限制。例如。我的似乎最大速度约为 350 MB/s
  • 这不是一个真正的 C++ 问题,它会归结为操作系统和硬件设施
  • 您正在阅读多少数据? KB/s 对于读取少量数据是很正常的(也许不是 ssd?)。我认为让程序并行也无济于事。如果我不得不猜测 SSD 一次只能传输一个请求。
  • @BradyDean M 为 4MB,N 几乎为 1024
  • 要获得 GB,您需要读取大型顺序文件。您正在阅读的文件是一百 MB 或更大。平行阅读也不会帮助你,也不会奏效。

标签: c++ io operating-system solid-state-drive


【解决方案1】:

无论您告诉fstream 阅读多少内容,都可能通过a fixed size streambuf buffer 完成。 C++ 标准没有指定其默认大小,但 4kb 相当普遍。因此,将 4mb 大小传递给 read() 很可能最终会有效地将其减少到 1024 次调用以读取 4kb 数据。这可能解释了您观察到的表现。您不是一次读取大量数据,而是您的应用程序多次调用以读取较小的数据块。

C++ 标准确实提供了通过 pubsetbuf 方法调整内部流缓冲区大小的方法,并将其留给每个 C++ 实现来准确指定何时以及如何使用非默认值配置流缓冲区尺寸。您的 C++ 实现可能只允许您在打开 std::ifstream 之前调整流缓冲区的大小,或者它可能根本不允许您调整 std::ifstream 的默认流缓冲区大小;相反,您必须先构造自定义流缓冲区实例,然后使用rdbuf() 将其附加到std::ifstream。有关详细信息,请参阅 C++ 库的文档。

或者,您可能希望考虑使用操作系统的本机文件输入/输出系统调用,并完全绕过流缓冲区库,这也会增加一些开销。文件的内容很可能首先被读入流缓冲区,然后复制到您在此处传递的缓冲区中。调用您的本机文件输入系统调用将消除这种冗余副本,从而提高一点性能。

【讨论】:

    【解决方案2】:

    您可能在尝试并行化 istream 对象上的 read() 调用时遇到了麻烦(本质上,这是一种串行机制)。

    来自cppreferenceistream::read(我的粗体字):

    修改s指向的数组和流中的元素 目的。 并发访问同一个流对象可能会导致数据 比赛,标准流对象 cin 除外 与 stdio 同步(在这种情况下,不会启动数据竞争, 虽然不保证提取的顺序 字符归属于线程)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-29
      • 2020-05-18
      • 2015-05-24
      • 2011-05-02
      • 1970-01-01
      • 2013-07-14
      • 1970-01-01
      • 2013-07-05
      相关资源
      最近更新 更多