【问题标题】:Is it better to read an entire file in std::string or to manipulate a file with std::ifstream?在 std::string 中读取整个文件还是使用 std::ifstream 操作文件更好?
【发布时间】:2015-02-16 15:34:57
【问题描述】:

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

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

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

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

【问题讨论】:

  • 访问内存总是比访问磁盘快。这实际上取决于您需要读取的数据量以及运行程序的上下文。我记得几年前,我不得不从一个大约 4MB 的文件中读取一些数据,而令人惊讶的是,它可以放入缓存中!在我的情况下,通过将所有数据加载到内存中,程序的速度大大提高了;)
  • 如果不进行测量,我猜让fstream 进行缓冲可能比将所有内容读入内存要快。它当然更简单,更具可扩展性,所以在你确定它是一个瓶颈之前这样做。但你应该衡量,而不是猜测。
  • 这个问题比 Stack Overflow 更适合programmers.stackexchange.com,因为您询问的是您想要设计/重构的代码,而不是存在且不起作用的代码
  • 是的,谢谢。

标签: c++ string ifstream


【解决方案1】:

看看mmap。此 API 允许您使用与 RAM 相同的分页机制将文件描述符映射到地址空间。通过这种方式,您既可以享受随机访问数据的好处,又不会不必要地将不需要的数据复制到 RAM 中。

【讨论】:

  • 好点。即使这个问题看起来更笼统(并且可能不完全是关于 SO 的主题)。
  • 还没想好,谢谢我会用这个API测量
【解决方案2】:

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

什么是堆分配的“大”?操作系统会试图欺骗您的进程,让您认为所有现有的工作内存都是空闲的。这实际上不是真的,如果某些进程请求太多内存,操作系统将“交换”一种类型的内存为另一种类型的内存。但原则上,如果堆分配与工作内存的总大小相当,您应该认为它是大的。

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

【讨论】:

  • 据我所知 ifstream 应该被缓冲所以速度差异可能比你想象的要小。在 unix 系统上,所有文件访问都由操作系统缓冲,这将加快速度。
  • @doron:磁盘访问比内存访问慢一个数量级。你不能用“缓冲”把它扔掉。
  • 但是将所有数据读入 RAM 不只是另一种形式的缓冲吗?
【解决方案3】:

(预计此问题将被关闭,因为它是一个“基于意见”的问题。)

我的想法:

  1. 这听起来像是过早的优化。用简单的方法写,如果太慢就优化。
  2. 在内存中工作通常要快数千倍。堆分配会根据分配的 number 而变慢,而不是根据分配的 size。不过,这听起来不像是在处理大量数据。
  3. 如果您的文件是“几 MB”,那么操作系统可能会缓存它。

【讨论】:

    【解决方案4】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      • 2011-02-05
      相关资源
      最近更新 更多