Vin*_*ent 55 c++ buffer fstream file c++11
我测试了两种写入配置:
1)Fstream缓冲:
// Initialization
const unsigned int length = 8192;
char buffer[length];
std::ofstream stream;
stream.rdbuf()->pubsetbuf(buffer, length);
stream.open("test.dat", std::ios::binary | std::ios::trunc)
// To write I use :
stream.write(reinterpret_cast<char*>(&x), sizeof(x));
Run Code Online (Sandbox Code Playgroud)
2)手动缓冲:
// Initialization
const unsigned int length = 8192;
char buffer[length];
std::ofstream stream("test.dat", std::ios::binary | std::ios::trunc);
// Then I put manually the data in the buffer
// To write I use :
stream.write(buffer, length);
Run Code Online (Sandbox Code Playgroud)
我期待同样的结果......
但是我的手动缓冲可以将性能提高10倍来写入100MB的文件,并且与正常情况相比,fstream缓冲不会改变任何东西(不重新定义缓冲区).
有人对这种情况有解释吗?
编辑:这是新闻:刚刚在超级计算机上完成的基准测试(Linux 64位架构,持续英特尔至强8核,Lustre文件系统和...希望配置良好的编译器)
(我没有解释1kB手动缓冲器"共振"的原因......)
编辑2:在1024 B的共振(如果有人对此有所了解,我很感兴趣):

Vau*_*ato 25
这基本上是由于函数调用开销和间接.ofstream :: write()方法继承自ostream.libstdc ++中没有内联该函数,这是第一个开销源.然后ostream :: write()必须调用rdbuf() - > sputn()来进行实际写入,这是一个虚函数调用.
最重要的是,libstdc ++将sputn()重定向到另一个虚函数xsputn(),它增加了另一个虚函数调用.
如果您自己将字符放入缓冲区,则可以避免这种开销.
小智 6
我想解释一下第二张图表中出现峰值的原因。
实际上,std::ofstream正如我们在第一张图片中看到的那样,使用的虚函数导致性能下降,但是并没有给出为什么最高性能是当手动缓冲区大小小于1024字节时的答案。
该问题与的高成本writev()和write()系统调用以及std::filebuf内部类的内部实现有关std::ofstream。
为了显示write()对性能的影响,我使用ddLinux计算机上的工具进行了一个简单测试,以复制具有不同缓冲区大小的10MB文件(bs选项):
test@test$ time dd if=/dev/zero of=zero bs=256 count=40000
40000+0 records in
40000+0 records out
10240000 bytes (10 MB) copied, 2.36589 s, 4.3 MB/s
real 0m2.370s
user 0m0.000s
sys 0m0.952s
test$test: time dd if=/dev/zero of=zero bs=512 count=20000
20000+0 records in
20000+0 records out
10240000 bytes (10 MB) copied, 1.31708 s, 7.8 MB/s
real 0m1.324s
user 0m0.000s
sys 0m0.476s
test@test: time dd if=/dev/zero of=zero bs=1024 count=10000
10000+0 records in
10000+0 records out
10240000 bytes (10 MB) copied, 0.792634 s, 12.9 MB/s
real 0m0.798s
user 0m0.008s
sys 0m0.236s
test@test: time dd if=/dev/zero of=zero bs=4096 count=2500
2500+0 records in
2500+0 records out
10240000 bytes (10 MB) copied, 0.274074 s, 37.4 MB/s
real 0m0.293s
user 0m0.000s
sys 0m0.064s
Run Code Online (Sandbox Code Playgroud)
如您所见,缓冲区越少,写入速度越低,并且dd在系统空间上花费的时间也就更多。因此,当缓冲区大小减小时,读/写速度会降低。
但是,为什么最快的速度是主题创建者手动缓冲区测试中的手动缓冲区大小小于1024字节时的结果?为什么几乎恒定?
解释与std::ofstream实现有关,尤其是与std::basic_filebuf。
默认情况下,它使用1024个字节的缓冲区(BUFSIZ变量)。因此,当您使用小于1024的内存块写入数据时,writev()(非write())系统调用至少两次执行两次ofstream::write()操作(内存块的大小为1023 <1024-第一个写入缓冲区,第二个强制写入第一个和第二个)。基于此,我们可以得出结论,ofstream::write()速度不取决于峰值之前的手动缓冲区大小(write()很少被称为两次)。
当您尝试使用ofstream::write()call 一次写入大于或等于1024字节的缓冲区时,writev()将为each 调用系统调用ofstream::write。因此,您看到当手动缓冲区大于1024(在峰值之后)时,速度会提高。
此外,如果您想使用std::ofstream大于1024的缓冲区(例如8192字节的缓冲区)来设置缓冲区,streambuf::pubsetbuf()并ostream::write()使用1024大小的块来调用写入数据,那么您将惊讶于写入速度将与使用1024缓冲区相同。这是因为实施std::basic_filebuf -内部类的std::ofstream-被硬编码强制呼叫系统writev()调用每个ofstream::write()时传递的缓冲区是调用大于或等于1024个字节(见basic_filebuf :: xsputn()的源代码)。也有在该报道在GCC的Bugzilla一个开放的问题,2014年11月5日。
因此,可以使用两种可能的情况解决此问题:
std::filebuf由您自己的班级替换并重新定义std::ofstreamofstream::write()小于1024的片段,然后ofstream::write()逐个传递给ofstream::write(),以免降低虚函数的性能std::ofstream