我的程序并行读取几十个非常大的文件,一次只读一行。似乎主要的性能瓶颈是HDD在文件之间寻找时间(虽然我不完全确定如何验证这一点),所以我认为如果我可以缓冲输入会更快。
我正在使用这样的C ++代码通过boost :: iostreams“过滤流”来读取我的文件:
input = new filtering_istream;
input->push(gzip_decompressor());
file_source in (fname);
input->push(in);
根据documentation,file_source
无法设置缓冲区大小,但filtering_stream :: push似乎:
void push( const T& t,
std::streamsize buffer_size,
std::streamsize pback_size );
所以我尝试了input->push(in, 1E9)
,确实我的程序的内存使用量大了,但速度根本没有变化。
读取缓冲是否会改善性能,我是错误的吗?或者我做错了吗?我可以直接缓冲file_source,还是需要创建filtering_streambuf?如果是后者,那怎么办?文档并没有完整的例子。
答案 0 :(得分:2)
您也应该对其进行分析,看看瓶颈在哪里。
也许它在内核中,也许是你的硬件限制。直到你描述它,发现你在黑暗中磕磕绊绊。
修改强>
好的,这次是一个更彻底的答案。根据Boost.Iostreams文档basic_file_source
只是std::filebuf
的包装,而std::streambuf
依赖于streambuf
。引用文档:
以只读模式打开的std :: basic_filebuf的CopyConstructible和Assignable包装器。
#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;
}
确实提供了一种方法pubsetbuf(可能不是最好的参考,但是第一个谷歌出现了),你可以用来控制缓冲区大小。
例如:
basic_file_sink
在我的测试中(虽然优化了)但实际上我使用4096字节缓冲区的性能比16字节缓冲区差但是YMMV - 这是为什么你应该总是首先分析它的一个很好的例子:)
但是,正如您所说,filebuf
没有提供任何方法来访问它,因为它隐藏了private part中的基础filebuf
。
如果您认为这是错误的,您可以:
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
包装器,它会公开缓冲区大小。本教程中有一个section解释了编写可能是一个很好的起点的自定义源。请记住,你的硬盘和内核已经对文件读取进行了缓存和缓冲,我认为你不会因为缓存而获得更多的性能提升。
最后,关于剖析的一个词。 Linux上有很多强大的分析工具,我甚至不知道它们中的一半,但是例如iotop有点整洁,因为它使用起来非常简单。它非常像top,而是显示与磁盘相关的指标。例如:
{{1}}
告诉我,我的程序花费了90%以上的时间等待IO,即它的IO绑定。如果您需要更强大的功能,我相信谷歌可以帮助您。
请记住,在热或冷缓存上进行基准测试会极大地影响结果。