fstream比fopen快吗?并随着缓冲区增加而变得更快?

时间:2019-07-05 22:24:47

标签: c++ io

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

  • 我增加了缓冲区大小以减少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 << char
更快 (否则,如果缓冲区<〜256,则fopen比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)
}

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:0)

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

setbuf actual 行为因实现而异:

  • libstdc ++:setbuf仅在打开文件之前调用时有效。除此之外,它还可以满足您的期望。每次缓冲区满时,您将获得对基础write系统调用的一个调用。
  • libc ++:setbuf可以在打开文件后但未完成任何I / O之前调用。每次缓冲区满时,您都会调用基础fwrite上的FILE*。这意味着仍使用FILE的内部缓冲区来缓冲输出。无法访问内部FILE*setbufsetvbuf上的内容,因此您将无法使用默认的缓冲区大小(在glibc的实现中,当前为4096字节)。 / li>
  • MSVCRT:basic_filebuf与基础FILE对象共享其缓冲区。 setbuf只是将您提供的缓冲区传递给对基础setvbuf的{​​{1}}的调用。可以随时调用,但是会丢弃任何先前缓冲的数据。