28

我一直听说 C++ 文件 I/O 操作比 C 风格的 I/O 慢得多。但是我没有找到任何关于它们实际上有多慢的实用参考,所以我决定在我的机器上测试它(Ubuntu 12.04,GCC 4.6.3,ext4 分区格式)。

首先我在磁盘上写了一个~900MB 的文件。

C++ ( ofstream): 163s

ofstream file("test.txt");
    
for(register int i = 0; i < 100000000; i++) 
    file << i << endl;

C ( fprintf): 12 秒

FILE *fp = fopen("test.txt", "w");
    
for(register int i = 0; i < 100000000; i++) 
    fprintf(fp, "%d\n", i);

我期待这样的输出,它表明在 C++ 中写入文件比在 C 中慢得多。然后我使用 C 和 C++ I/O 读取相同的文件。是什么让我惊呼从文件读取时性能几乎没有差异。

C++ ( ifstream): 12 秒

int n;
ifstream file("test.txt");

for(register int i = 0; i < 100000000; i++) 
    file >> n;

C ( fscanf): 12 秒

FILE *fp = fopen("test.txt", "r");
    
for(register int i = 0; i < 100000000; i++) 
    fscanf(fp, "%d", &n);

那么,为什么使用流执行写入需要这么长时间?或者,为什么使用流读取比写入快?

结论:罪魁祸首是std::endl,正如答案和评论所指出的那样。将线路更改 file << i << endl;file << i << '\n';已将运行时间从 163 秒减少到 16 秒。

4

3 回答 3

29

您正在使用endl打印换行符。这就是这里的问题,因为它不仅仅是打印换行符—— endl刷新缓冲区,这是一项昂贵的操作(如果你在每次迭代中都这样做)。

\n如果你的意思是这样,请使用:

file << i << '\n';

而且,必须在发布模式下编译您的代码(即打开优化)。

于 2013-07-04T10:44:32.933 回答
22

不,C++ 输入/输出并不比 C 慢很多——如果有的话,现代实现在格式化输入/输出上应该稍微快一些,因为它不需要解析格式字符串,而是在编译时通过流操作符的链接。

以下是在基准测试中需要考虑的一些注意事项:

  • 使用完全优化 ( ) 进行编译-O3以获得公平的比较。
  • 适当的基准测试需要估计偏差——实际上这意味着您需要重复测试并将它们交错。目前,您的代码对来自后台进程的干扰并不健壮。您还应该报告重复运行的汇总统计数据,以捕获扭曲估计的异常值。
  • 禁用与 C 流的 C++ 流同步 ( std::ios_base::sync_with_stdio(false);)
  • 使用'\n'代替(冲洗)std::endl
  • 不要使用register声明——它根本没有区别,现代编译器可能无论如何都会忽略它。
于 2013-07-04T10:47:04.990 回答
1

使用 处理大文件时fstream,请确保将流缓冲区设置为 >0

与直觉相反,禁用流缓冲会显着降低性能。至少 MSVC 2015 实现一次将 1 个字符复制到filebuf未设置缓冲区时(请参阅 参考资料streambuf::xsputn),这会使您的应用程序受 CPU 限制,从而导致 I/O 速率降低。

const size_t bufsize = 256*1024;
char buf[bufsize];
mystream.rdbuf()->pubsetbuf(buf, bufsize);

您可以在此处找到完整的示例应用程序。

于 2016-08-23T10:06:36.553 回答