C ++标准是否要求iostream的性能不佳,或者我只是处理糟糕的实现?
每当我提到C ++标准库iostream的慢性能时,我都会遇到一阵难以置信的风潮。然而,我有剖析器结果显示在iostream库代码中花费了大量时间(完全编译器优化),并且从iostream切换到特定于操作系统的I / O API和自定义缓冲区管理确实提供了一个数量级的改进。
C ++标准库做了多少额外工作,标准是否需要它,它在实践中是否有用?或者有些编译器提供了与手动缓冲区管理竞争的iostream实现吗?
为了解决问题,我编写了几个简短的程序来练习iostreams内部缓冲:
将二进制数据放入ostringstream
http://ideone.com/2PPYw
将二进制数据放入char[]
缓冲区http://ideone.com/Ni5ct
vector<char>
使用http://ideone.com/Mj2Fi将二进制数据放入其中back_inserter
新:vector<char>
简单的迭代器http://ideone.com/9iitv
新:将二进制数据直接放入stringbuf
http://ideone.com/qc9QA
新:vector<char>
简单的迭代器加边界检查http://ideone.com/YyrKy
请注意,ostringstream
和stringbuf
版本运行的迭代次数较少,因为它们的速度要慢得多。
在ideone上,它ostringstream
比std:copy
+ back_inserter
+ 慢大约3倍std::vector
,比memcpy
原始缓冲区慢大约15倍。当我将实际应用程序切换到自定义缓冲时,这与前后分析一致。
这些都是内存缓冲区,因此iostream的缓慢不能归咎于缓慢的磁盘I / O,过多的刷新,与stdio的同步,或者人们用来解释C ++标准库观察到的缓慢的任何其他事情iostream的。
很高兴看到其他系统上的基准测试和常见实现的评论(例如gcc的libc ++,Visual C ++,Intel C ++)以及标准规定了多少开销。
许多人都正确地指出,iostream更常用于格式化输出。但是,它们也是C ++标准提供的二进制文件访问的唯一现代API。但是对内部缓冲进行性能测试的真正原因适用于典型的格式化I / O:如果iostreams无法保持磁盘控制器提供原始数据,那么当他们负责格式化时,他们怎么可能跟上呢?
所有这些都是outer(k
)循环的每次迭代。
在ideone上(gcc-4.3.4,未知的操作系统和硬件):
ostringstream
:53毫秒
stringbuf
:27毫秒
vector<char>
并且back_inserter
:17.6毫秒
vector<char>
与普通迭代器:10.6毫秒
vector<char>
迭代器和边界检查:11.4 ms
char[]
:3.7毫秒
在我的笔记本电脑上(Visual C ++ 2010 x86,cl /Ox /EHsc
Windows 7旗舰版64位,Intel Core i7,8 GB RAM):
ostringstream
:73.4毫秒,71.6毫秒
stringbuf
:21.7 ms,21.3 ms
vector<char>
和back_inserter
:34.6毫秒,34.4毫秒
vector<char>
与普通迭代器:1.10毫秒,1.04毫秒
vector<char>
迭代器和边界检查:1.11 ms,0.87 ms,1.12 ms,0.89 ms,1.02 ms,1.14 ms
char[]
:1.48毫秒,1.57毫秒
VISUAL C ++ 2010 x86上,与档案导引优化cl /Ox /EHsc /GL /c
,link /ltcg:pgi
运行,link /ltcg:pgo
,措施:
ostringstream
:61.2 ms,60.5 ms
vector<char>
与普通迭代器:1.04毫秒,1.03毫秒
相同的笔记本电脑,相同的操作系统,使用cygwin gcc 4.3.4 g++ -O3
:
ostringstream
:62.7 ms,60.5 ms
stringbuf
:44.4毫秒,44.5毫秒
vector<char>
和back_inserter
:13.5毫秒,13.6毫秒
vector<char>
使用普通迭代器:4.1 ms,3.9 ms
vector<char>
迭代器和边界检查:4.0毫秒,4.0毫秒
char[]
:3.57毫秒,3.75毫