C和C ++样式文件IO之间的性能差异
我一直听说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
):12s
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
):12s
int n; ifstream file("test.txt"); for(register int i = 0; i > n;
C( fscanf
):12s
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秒。
您正在使用endl
来打印换行符。 这就是问题,因为它不仅仅是打印换行符 – endl
还会刷新缓冲区,这是一项昂贵的操作(如果你在每次迭代中都这样做)。
如果你这样说,请使用\n
:
file << i << '\n';
而且,必须在发布模式下编译代码(即打开优化)。
不,C ++输入/输出并不比C慢 – 如果有的话,现代实现应该在格式化的输入/输出上稍快一些,因为它不需要解析格式字符串,而是在编译时确定格式化流运营商的链接。
以下是基准测试中需要考虑的一些注意事项:
- 使用完全优化(
-O3
)进行编译以获得公平的比较。 - 一个适当的基准需要估计偏差 – 实际上这意味着你需要重复你的测试并交错它们。 目前,您的代码对后台进程的干扰不稳健。 您还应该报告重复运行的摘要统计信息,以捕获扭曲估计值的exception值。
- 禁用与C流的C ++流同步(
std::ios_base::sync_with_stdio(false);
) - 使用
'\n'
而不是(刷新)std::endl
- 不要使用
register
声明 – 它根本没有区别,现代编译器可能无论如何都会忽略它。
使用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);
您可以在此处找到完整的示例应用程序。