关于iostream的效率问题
2014-03-05 13:38
218 查看
前言
经常有人说iostream的速度慢,IO流比stdio的慢多了。但是有人测试过的,iostream的速度是超过stdio的。
测试结果
/* C */
#include <stdio.h>
int main()
{
FILE* stream;
size_t num;
size_t sum = 0;
size_t i = 0;
stream = fopen("random.data", "r");
while(fscanf(stream, "%u", &num) != EOF)
{
sum += num;
}
fclose(stream);
printf("%u\n", sum);
return 0;
}
/* C++ */
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream stream("random.data");
size_t num;
size_t sum = 0;
while(stream >> num)
{
sum += num;
}
cout << sum << endl;
return 0;
}
random.data中为100000个0-32767的随机数
C版本平均用时0.64s,C++平均用时0.58s
于是又把这陈芝麻烂谷子事拿出来研究。单步VC10/11(用后者是因为新版加入了chrono方便计时),cout输出一段字符串的调用顺序如下:
operator<< => sputn => xsputn => overflow => _Fputc => fputc
cout封装了fputc一个字符一个字符的输出,而Win下默认不给stdout开buffer,于是造成cout输出字符串极度缓慢,杯具出现了
想起线程安全性问题。cout虽然线程安全(原文:http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx),但是输出的字符是混在一起的,我猜想也是cout封装fputc而在fputc里加锁的原因。
看printf()的源码:
va_start(arglist, format);
_lock_str2(1, stdout);
__try {
// int _stbuf(stream) - set temp buffer on stdout, stdprn, stderr
buffing = _stbuf(stdout);
retval = _output_l(stdout,format,NULL,arglist);
// void _ftbuf(flag, stream) - take temp buffering off a stream
_ftbuf(buffing, stdout);
}
__finally {
_unlock_str2(1, stdout);
}
首先将stdout整体加锁,然后给stdout开了一个临时buffer,输出后再刷新,显然要比cout快得多。
测试用了fstream,文件指针在win下是默认开buffer的,于是给cout手动开buffer,前后测试结果如下:
未开buffer:
开了buffer:
可以看到未开buffer时cout的用时比printf慢数十倍,开buffer后的用时与printf已经十分接近(cout绑定stdout,给cout开buffer就等于给printf开buffer),造成的差异应该是每个字符分别加锁的缘故。另外printf用%s输出比直接输出快,大概是因为直接输出的话解析格式字符串时每个字符都要判断format
=='%'
这是g++ MinGW-w64的测试结果:
未开buffer:
开了buffer:
stdlibc++使用了不同的封装方式,未开buffer时两者速度已经较为接近,开buffer后已经超过用printf直接输出。
关于g++和VC的速度比较,除了原生64位以外,CRT也有差距,毕竟VC是微软自己的东西
注:mingw的cout.rdbuf()->pubsetbuf似乎有问题,改用setvbuf
附虚拟机下Fedora 16(g++ 4.6.2)测试结果(linux默认给stdout开buffer)
TIP:
关于cout输出慢,可能是buffer刷新的问题 把endl换成'\n'就会快上许多了。
经常有人说iostream的速度慢,IO流比stdio的慢多了。但是有人测试过的,iostream的速度是超过stdio的。
测试结果
/* C */
#include <stdio.h>
int main()
{
FILE* stream;
size_t num;
size_t sum = 0;
size_t i = 0;
stream = fopen("random.data", "r");
while(fscanf(stream, "%u", &num) != EOF)
{
sum += num;
}
fclose(stream);
printf("%u\n", sum);
return 0;
}
/* C++ */
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream stream("random.data");
size_t num;
size_t sum = 0;
while(stream >> num)
{
sum += num;
}
cout << sum << endl;
return 0;
}
random.data中为100000个0-32767的随机数
C版本平均用时0.64s,C++平均用时0.58s
于是又把这陈芝麻烂谷子事拿出来研究。单步VC10/11(用后者是因为新版加入了chrono方便计时),cout输出一段字符串的调用顺序如下:
cout封装了fputc一个字符一个字符的输出,而Win下默认不给stdout开buffer,于是造成cout输出字符串极度缓慢,杯具出现了
想起线程安全性问题。cout虽然线程安全(原文:http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx),但是输出的字符是混在一起的,我猜想也是cout封装fputc而在fputc里加锁的原因。
看printf()的源码:
va_start(arglist, format);
_lock_str2(1, stdout);
__try {
// int _stbuf(stream) - set temp buffer on stdout, stdprn, stderr
buffing = _stbuf(stdout);
retval = _output_l(stdout,format,NULL,arglist);
// void _ftbuf(flag, stream) - take temp buffering off a stream
_ftbuf(buffing, stdout);
}
__finally {
_unlock_str2(1, stdout);
}
首先将stdout整体加锁,然后给stdout开了一个临时buffer,输出后再刷新,显然要比cout快得多。
测试用了fstream,文件指针在win下是默认开buffer的,于是给cout手动开buffer,前后测试结果如下:
未开buffer:
=='%'
这是g++ MinGW-w64的测试结果:
未开buffer:
关于g++和VC的速度比较,除了原生64位以外,CRT也有差距,毕竟VC是微软自己的东西
注:mingw的cout.rdbuf()->pubsetbuf似乎有问题,改用setvbuf
附虚拟机下Fedora 16(g++ 4.6.2)测试结果(linux默认给stdout开buffer)
关于cout输出慢,可能是buffer刷新的问题 把endl换成'\n'就会快上许多了。
相关文章推荐
- 关于 while(1)和for(;;)效率问题的一点想法
- 关于逻辑运算符书写效率问题 和数组 处理问题
- 关于thinkphp关联模型的效率问题
- 关于StringBuilder和String的效率问题
- 关于CSS选择器的效率问题
- 关于语言的执行效率问题
- 关于多层for循环迭代的效率优化问题
- 来谈谈关于Shell中效率的问题
- 转AskTom:Oracle中关于in跟Exist谁效率高的问题。
- 关于效率问题的一点心得
- 关于读文本文件的效率问题[原创]
- 关于无限级分类数据库表结构设计问题,遍历某分类下所有产品 效率 (两张表) (一张表)
- 关于字符串效率问题
- 关于文件拷贝效率问题(面试总结)
- [LeetCode] Path Sum II, 关于效率的两个问题: vector还是queue? 传递引用还是拷贝?
- 关于ArrayList的初始容量以及扩容的效率问题
- 关于嵌套和连接的效率问题
- 关于VC数据库开发中数据库连接与效率的问题-----一点体会和经验
- 关于for循环的执行效率的问题
- 关于开发效率和项目周期的问题