【问题标题】:Reading small separated chunks of a large file (C++)读取大文件的小块(C++)
【发布时间】:2017-10-17 13:40:13
【问题描述】:

我正在阅读一种专有的二进制数据文件格式。格式基本上是 header, data, size_of_previous_data, header, data, size_of_previous_data, header, data, size_of_previous_data, ... 标头的一部分包括下一个数据块的字节数以及紧随数据后列出的大小。标头为 256 字节,数据通常约为 2MB,size_of_previous_data 是 32 位整数。

文件一般都很大~GB,我经常要在几十个文件中搜索我想要的数据。为了做到这一点,我在代码中做的第一件事是 idex 每个文件,即只读取标题并记录相关数据的位置(文件和字节数)。我的代码基本上使用 fstream::read() 准备好标头,检查数据大小,使用 fstream::seekg() 跳过数据,然后读入 size_of_previous_data,然后重复直到我到达文件末尾。

我的问题是这个索引非常缓慢。数据位于我的 Windows 10 笔记本电脑的内部 7200 rpm 硬盘驱动器上,任务管理器显示我的硬盘驱动器使用率已达到极限,但我的读取速度仅为 1.5 MB/s,响应时间通常 > 70 ms。我正在使用 std::fstream 读取文件,使用 fstream::get() 读取标题并使用 fstream::seekg() 移动到下一个标题。

我已经分析了我的代码,几乎所有时间都花在 fstream::read() 代码中以读取 size_of_previous_data 值。我假设当我这样做时,紧随其后的数据会被缓冲,因此我的 fstream::read() 获取下一个标头几乎不需要时间。

所以我想知道是否有办法优化这个?几乎我在任何缓冲读取中的整个缓冲区都可能被浪费(如果是 8kB 缓冲区,则其中的 97%)。有没有办法缩小它,是否值得(也许底层操作系统缓冲区也以我无法更改的方式)?

【问题讨论】:

  • 为什么不把开头的文件都读一遍呢? GB 的 RAM 通常没问题,但搜索 GB 大小的文件很慢也不足为奇
  • 如果数据的大小已经存储在标头中,为什么在查找数据时不跳过size_of_previous_data?您可以保存读取,直到您需要读取数据本身,然后将其用作一种校验和。如果您一次只读取 256 个字节,那么您不需要比这更大的缓冲区。
  • 如果您的操作系统支持,请尝试内存映射您的文件。操作系统将为您处理将块读取到内存中。
  • @tobi303 目前我需要读取的文件总大小为 11 GB,但我目前正在处理测试数据,这将很快增加到 44 GB,甚至更多。我的笔记本电脑有 8 GB 内存,所以我通过阅读所有内容来做的就是让我猜想引起抖动。
  • @ThomasMatthews 内存映射可能会明显更快吗?还是它会完全按照我在幕后所做的那样做?这是我问题的症结所在。我在问是否有人已经知道这样做的好策略,或者我是否需要花费大量时间测试内存映射之类的东西,并且可能会发现性能没有明显变化。

标签: c++ file io binary buffer


【解决方案1】:

假设磁盘查找大约需要 10 毫秒(来自 Latency Numbers Every Programmer Should Know),您的文件为 11 GB,由 2 MB 块组成,理论上最小运行时间为 5500 * 10 毫秒 = 55 秒。

如果您已经处于这个数量级,那么加快速度的最有效方法可能是购买 SSD。

【讨论】:

  • 假设磁盘查找大约需要 10 毫秒 这实际上是相当乐观的。 7,200 RPM SATA 磁盘通常在 15 毫秒范围内,而 5,400 RPM 驱动器可以超过 20 毫秒。但我想知道磁盘的带宽。 70 毫秒内的 2 MB 仅为 28 MB/秒。即使假设 70 毫秒中的 20 毫秒是寻道时间,这也意味着磁盘仅以 40 MB/秒的速度移动。这很低,而且数据路径上可能存在其他硬件瓶颈,这意味着 SSD 不会有太大帮助。
  • 如果我正确理解了这个问题,构建索引只需要读取 256 个字节,而不是完整的 2 MB。因此,寻道时间成为瓶颈,而不是带宽。
猜你喜欢
  • 1970-01-01
  • 2014-09-26
  • 2018-09-25
  • 1970-01-01
  • 1970-01-01
  • 2012-02-12
  • 2021-01-06
  • 2012-01-11
  • 2017-11-10
相关资源
最近更新 更多