在 std::string 中读取整个文件还是在 std::ifstream 中操作文件更好?

Is it better to read an entire file in std::string or to manipulate a file with std::ifstream?

我实际上正在开发科学的 C++ 模拟程序,这些程序读取数据,从中计算大量值,最后将结果存储在一个文件中。我想知道在程序开始时一次读取所有数据是否比在程序期间通过 std::ifstream 继续访问文件更快。

我使用的数据不是很大(几MB),但我什至不知道"big" 是什么堆分配...

我想这取决于数据等等(经过一些测试,实际上它取决于),但我想知道它取决于什么以及是否有一种我们应该遵循的一般原则。

长话短说,问题是:保持文件打开并使用文件操纵器是否比潜在的大堆分配和使用字符串操纵器更快?

(预计此问题会被关闭,因为这是一个 "opinion based" 问题。)

我的想法:

  1. 这听起来像是过早的优化。写的简单点,嫌慢再优化
  2. 在内存中工作通常要快数千倍。堆分配减慢基于分配的 number,而不是分配的 size。不过,这听起来不像是在处理大量数据。
  3. 如果你的文件是 "several MB" 那么 OS 可能无论如何都会缓存它。

看看mmap。 API 允许您使用与 RAM 相同的分页机制将文件描述符映射到您的地址 space。这样,您应该既能获得随机访问数据的好处,又不会不必要地将不需要的数据复制到 RAM 中。

在程序开始时一次读取所有数据是否比在程序期间通过std::ifstream继续访问文件更快?是的,可能是这样。请记住,工作内存速度快且价格昂贵,而存储内存(硬盘驱动器)的存在恰恰是以速度慢为代价的。

堆分配的 "big" 是什么? 操作系统将试图欺骗您的进程,使其认为所有现有的工作内存都是空闲的。这实际上不是真的,如果某些进程请求太多内存,OS 将 "swap" 一种类型的内存用于另一种类型的内存。但原则上,如果堆分配与工作内存的总大小相当,你应该认为堆分配很大。

保持文件打开并使用文件操纵器是否比潜在的大堆分配和使用字符串操纵器更快?不,它并不快,但它有另一个优势:它具有内存效率。如果您只将需要的数据放入内存以便使用它们,那么您就是在为机器中的所有其他进程(例如,可能是您程序的其他线程)节省内存。这是一个非常有趣的 属性 为了具有可扩展性的软件。

从大块文件中读取数据比许多小尺寸读取请求快得多。例如,10MB 的 1 次读取比 1MB 的 10 次读取更快。

当我优化文件I/O时,我将数据读入uint8_t缓冲区,然后解析缓冲区。这种方法的一个棘手问题是读取文本文件。文本编码数据有可能跨越缓冲区边界。例如,每个文本行有 4 个数字,缓冲区中只有 2 个(或者缓冲区中只有 2 位数字)。您将不得不编写代码来处理这些情况。

如果您将您的程序视为一个流水线,您或许可以进一步优化。您可以实现线程:读取线程、处理线程和写入(输出)线程。读取线程读取缓冲区。当有足够的数据进行处理时,读取线程唤醒处理线程。处理线程处理读取的数据,当有输出时,将其存储到共享缓冲区中并唤醒输出线程。所以有了管道模型,数据通过读取线程进入管道。在管道中的某个点,处理线程处理数据。写入线程从处理线程中获取数据并将其输出(退出管道)。

此外,组织您的数据使其适合处理器高速缓存行也将加速您的程序。