【问题标题】:fstream faster than fopen? and gets faster as buffers increase?fstream 比 fopen 快?并随着缓冲区的增加而变得更快?
【发布时间】:2019-11-16 11:37:30
【问题描述】:

我一直在尝试尽可能快地写入文件数据。

  • 我增加了缓冲区大小以减少 i/o 操作。
  • 我已经使用 fstream 和 fopen 进行了测试。

由于某种原因,fstream 比 fopen 快。

  • 在 64 字节缓冲区上,它的速度提高了约 1.3 倍
  • 在 8192 字节缓冲区上,它的速度提高了约 4.8 倍。

我一直听说 C 的文件 I/O 更快(这是有道理的)
<fstream> 包括 <stdio.h> 但我无法让 fopen 执行得这么快。

注意(旧问题):

  • 我的 fopen 比 fstream 慢 2 倍,因为我使用了 fprintf(感谢 jamesdlin
  • fstream 缓冲区没有改变,因为您必须在打开之前设置它(感谢Paul Sanders

也实现了 fstream.put(char) 比 fstream 快 (否则,如果缓冲区

这是我的测试:

#include <iostream>
#include <fstream>
#include <ctime>

int filesize; // total bytes (individually "put" in buffered stream)
int buffsize; // buffer size

void writeCPP(){
    std::ofstream file;
    char buffer[buffsize]; file.rdbuf()->pubsetbuf(buffer,buffsize);    // set buffer (before opening)
    file.open("test.txt",std::ios::binary);                             // open file
    for(int i=0; i<filesize; i++) file.put('a');                        // write bytes
    file.close();                                                       // close
}

void writeC(){
    FILE* file=fopen("test.txt","wb");                                  // open file
    char buffer[buffsize]; setvbuf(file,buffer,_IOFBF,buffsize);        // set buffer
    for(int i=0; i<filesize; i++) fputc('a',file);                      // write bytes
    fclose(file);                                                       // close
}

#define getTime() double(clock())/CLOCKS_PER_SEC // good enough

double start;

void test(int s){ // C++ vs C (same filesize / buffsize)
    buffsize=s;
    std::cout<<"  buffer: "<<buffsize<<"\t"<<std::flush;

    start=getTime();
    writeCPP();
    std::cout<<"  C++: "<<getTime()-start<<",\t"<<std::flush;

    start=getTime();
    writeC();
    std::cout<<" C: "<<getTime()-start<<std::endl;
}

#define MB (1024*1024)

int main(){
    filesize=10*MB;
    std::cout<<"size: 10 MB"<<std::endl;

    // C++ fstream faster
    test(64);   // C++ 0.86 < C 1.11 (1.29x faster)
    test(128);  // C++ 0.44 < C 0.79 (1.80x faster) (+0.51x)
    test(256);  // C++ 0.27 < C 0.63 (2.33x faster) (+0.53x)
    test(512);  // C++ 0.19 < C 0.56 (2.94x faster) (+0.61x)
    test(1024); // C++ 0.15 < C 0.52 (3.46x faster) (+0.52x)
    test(2048); // C++ 0.14 < C 0.51 (3.64x faster) (+0.18x)
    test(4096); // C++ 0.12 < C 0.49 (4.08x faster) (+0.44x)
    test(8192); // C++ 0.10 < C 0.48 (4.80x faster) (+0.72x)
}

【问题讨论】:

  • 我没有读到你的测量方法——你做错了。
  • @TedLyngmo 该评论令人难以理解。
  • 另外,发现 C++ 流变慢并不是“攻击”。
  • 呃,这个问题不是声称 C++ 流比 C 流吗? C++ 如何“受到攻击”是任何意义?
  • @jamesdlin 谢谢!解决了它。哈哈,终于有人真正想帮忙了!

标签: c++ io


【解决方案1】:

WriteCPP,你必须在打开文件之前设置缓冲区,像这样:

std::ofstream file;
char buffer[BUFF]; file.rdbuf()->pubsetbuf(buffer, BUFF);   // set buffer
file.open ("test.txt", std::ios::binary);                   // open file

然后您会得到您可能期望的结果(时间是写入 20MB 并显示缓冲区大小):

writeCPP, 32: 2.15278
writeCPP, 128: 1.21372
writeCPP, 512: 0.857389

我还对 WriteC 进行了基准测试,将您从 fprintf 更改为 fputc 并得到以下结果(再次写入 20MB):

writeC, 32: 1.41433
writeC, 128: 0.524264
writeC, 512: 0.355097

测试程序在这里:

https://wandbox.org/permlink/F2H2jcrMVsc5VNFf

【讨论】:

  • 有趣的是,在我的设备(MacOS,Apple LLVM 版本 10.0.1 (clang-1001.0.46.4),-O2)上,cpp 的性能仍然明显优于 c(与OP正在看到)。 wandbox here 上的预期结果,我的装备上的实际结果(相同代码)here
  • @WhozCraig 看起来 libc++ 的 basic_filebuf 在底层使用了 FILE*,而 FILE 有自己的缓冲区,您无法更改。这意味着如果缓冲区大小不是 FILE 的默认缓冲区大小的倍数(我的副本上为 4096),您将得到奇怪的结果。
【解决方案2】:

fprintf 有额外的开销,因为它需要扫描其输入字符串以查找格式说明符,因此您并没有完全进行苹果对苹果的比较。

更好的比较是使用fputs 而不是fprintf 或使用fputc 然后在iostream 版本中使用file &lt;&lt; 'a'

【讨论】:

  • 再次感谢。我已将问题更新为现在仅与缓冲区有关。 (因为我仍然无法通过改变它来获得更好的性能)
【解决方案3】:

std::basic_filebuf::setbuf 的唯一标准定义行为是 setbuf(0, 0) 将流设置为无缓冲输出,即使那样我也不会指望它。

setbuf实际行为因实施而异:

  • libstdc++:setbuf 仅在打开文件之前调用才有效。除此之外,它会做你可能期望的事情。每次缓冲区填满时,您都会收到一个对底层 write 系统调用的调用。
  • libc++:setbuf 可以在打开文件之后调用,但在任何 I/O 完成之前。每次缓冲区填满时,您都会在底层FILE* 上调用fwrite。这意味着输出仍然使用FILE 的内部缓冲区进行缓冲。无法访问内部的FILE*setbufsetvbuf,因此您只能使用默认缓冲区大小(目前至少在 glibc 的实现中为 4096 字节)。
  • MSVCRT:basic_filebuf 与其底层FILE 对象共享其缓冲区。 setbuf 只是将你给它的缓冲区传递给对底层FILE*setvbuf 的调用。可以随时调用,但会丢弃任何先前缓冲的数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-09
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    • 2019-02-08
    • 1970-01-01
    • 2016-01-21
    相关资源
    最近更新 更多