如何使用boost :: iostreams更改缓冲区大小?

use*_*250 6 c++ boost

我的程序并行读取几十个非常大的文件,一次只读一行.似乎主要的性能瓶颈是HDD在文件之间寻找时间(虽然我不完全确定如何验证这一点),所以我认为如果我可以缓冲输入会更快.

我正在使用这样的C++代码通过boost :: iostreams"过滤流"来读取我的文件:

input = new filtering_istream;
input->push(gzip_decompressor());
file_source in (fname);
input->push(in);
Run Code Online (Sandbox Code Playgroud)

根据文档,file_source没有任何方法来设置缓冲区大小,但filtering_stream :: push似乎:

void push( const T& t,
  std::streamsize buffer_size,
  std::streamsize pback_size );
Run Code Online (Sandbox Code Playgroud)

所以我尝试了input->push(in, 1E9),确实我的程序的内存使用量大了,但速度根本没有变化.

我认为读取缓冲会改善性能是错误的吗?或者我做错了吗?我可以直接缓冲file_source,还是需要创建filtering_streambuf?如果是后者,那怎么办?文档并不完全是示例.

Sta*_*fan 2

您也应该对其进行分析,看看瓶颈在哪里。

也许它在内核中,也许是你的硬件限制。直到你分析它才发现你在黑暗中跌跌撞撞。

编辑:

好吧,这次的答案更加彻底。根据 Boost.Iostreams 文档,basic_file_source它只是一个包装器std::filebuf,而它又是建立在std::streambuf. 引用文档:

以只读模式打开的 std::basic_filebuf 的可复制构造和可分配包装器。

streambuf确实提供了一种方法pubsetbuf(也许不是最好的参考,但第一个谷歌出现),显然,您可以使用它来控制缓冲区大小。

例如:

#include <fstream>

int main()
{
  char buf[4096];
  std::ifstream f;
  f.rdbuf()->pubsetbuf(buf, 4096);
  f.open("/tmp/large_file", std::ios::binary);

  while( !f.eof() )
  {
      char rbuf[1024];
      f.read(rbuf, 1024);
  }

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

在我的测试中(虽然优化关闭),实际上,4096 字节缓冲区的性能比 16 字节缓冲区的性能更差,但是 YMMV —— 这是为什么您应该始终首先分析的一个很好的例子:)

但是,正如您所说,它basic_file_sink不提供任何访问它的方法,因为它将底层隐藏filebuf在其私有部分中。

如果您认为这是错误的,您可以:

  1. 敦促 Boost 开发人员公开此类功能,使用邮件列表或 trac。
  2. 构建您自己的filebuf包装器,它会公开缓冲区大小。本教程中有一个部分解释了编写自定义源代码,这可能是一个很好的起点。
  3. 根据任何内容编写自定义源,它可以完成您想要的所有缓存。

请记住,您的硬盘驱动器和内核已经对文件读取进行了缓存和缓冲,我认为您不会从缓存中获得更多的性能提升。

最后,谈谈分析。Linux 有大量强大的分析工具,我什至不知道其中一半的名称,但例如iotop,它很简洁,因为它使用起来超级简单。它与 top 非常相似,但显示了与磁盘相关的指标。例如:

Total DISK READ: 31.23 M/s | Total DISK WRITE: 109.36 K/s
TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND          
19502 be/4 staffan    31.23 M/s    0.00 B/s  0.00 % 91.93 % ./apa
Run Code Online (Sandbox Code Playgroud)

告诉我我的程序花费了超过 90% 的时间等待 IO,即它是 IO 绑定的。如果您需要更强大的东西,我相信谷歌可以帮助您。

请记住,对热缓存或冷缓存进行基准测试会极大地影响结果。