C ++标准是否要求iostream的性能不佳,或者我只是处理糟糕的实现?

时间:2010-12-02 21:57:02

标签: c++ performance iostream

4 个答案:

答案 0 :(得分:47)

没有像标题那样回答你的问题的具体细节:2006 Technical Report on C++ Performance有一个关于IOStreams的有趣部分(第68页)。与您的问题最相关的是第6.1.2节(“执行速度”):

  

由于IOStreams处理的某些方面是   它分布在多个方面   似乎标准规定了一个   效率低下。但是这个   事实并非如此 - 通过使用某种形式   预处理,大部分工作都可以   要避免。稍微聪明一些   通常使用的链接器,它是   可以删除其中的一些   效率低下。这将在讨论中   §6.2.3和§6.2.5。

由于该报告是在2006年编写的,人们希望许多建议能够被纳入当前的编译器中,但也许情况并非如此。

正如您所提到的,write()中的方面可能没有特征(但我不会盲目地假设)。那么功能是什么?在使用GCC编译的ostringstream代码上运行GProf会产生以下细分:

  • std::basic_streambuf<char>::xsputn(char const*, int)
  • 中的44.23%
  • std::ostream::write(char const*, int)
  • 中的34.62%
  • main
  • 中的12.50%
  • std::ostream::sentry::sentry(std::ostream&)
  • 中的6.73%
  • std::string::_M_replace_safe(unsigned int, unsigned int, char const*, unsigned int)
  • 中的0.96%
  • std::basic_ostringstream<char>::basic_ostringstream(std::_Ios_Openmode)
  • 中的0.96%
  • std::fpos<int>::fpos(long long)
  • 中的0.00%

因此,大部分时间花在xsputn上,在大量检查和更新光标位置和缓冲区之后最终调用std::copy()(详情请查看c++\bits\streambuf.tcc )。

我对此的看法是,你专注于最坏情况。如果您处理的是相当大的数据块,那么所执行的所有检查都只是完成的总工作量的一小部分。但是您的代码一次只能以四个字节的速度移动数据,并且每次都会产生所有额外成本。显然,人们会避免在现实生活中这样做 - 考虑如果在一个1m整数的数组上调用write而不是在一个int上调用1m次,那么惩罚是多么微不足道。在现实生活中,人们会非常欣赏IOStream的重要特性,即内存安全和类型安全设计。这样的好处是有代价的,你编写了一个测试,使这些成本占据执行时间。

答案 1 :(得分:27)

我对Visual Studio用户感到非常失望,他们更喜欢这个用户:

  • ostream的Visual Studio实现中,sentry对象(标准所需)进入保护streambuf的关键部分(这不是必需的)。这似乎不是可选的,因此即使对于单个线程使用的本地流,也需要支付线程同步的成本,而不需要同步。

这会伤害使用ostringstream严格格式化邮件的代码。使用stringbuf直接避免使用sentry,但格式化的插入运算符无法直接在streambuf上运行。对于Visual C ++ 2010,关键部分将ostringstream::write与基础stringbuf::sputn调用相比减慢了三倍。

看看beldaz's profiler data on newlib,似乎很明显gcc的sentry并没有像这样疯狂。 gcc下的ostringstream::write仅比stringbuf::sputn长约50%,但stringbuf本身比VC ++慢得多。并且两者仍然比较使用vector<char>进行I / O缓冲非常不利,尽管与VC ++下的边距不同。

答案 2 :(得分:8)

你看到的问题是每次调用write()时的开销。你添加的每个抽象级别(char [] - &gt; vector - &gt; string - &gt; ostringstream)都会增加一些函数调用/返回和其他内务处理guff,如果你称之为一百万次 - 加起来。 / p>

我修改了ideone上的两个示例,一次写入十个整数。 ostringstream时间从53到6毫秒(几乎提高了10倍),而char循环改进了(3.7到1.5) - 很有用,但只有两倍。

如果您担心性能,那么您需要为工作选择合适的工具。 ostringstream是有用且灵活的,但是按照你想要的方式使用它会受到惩罚。 char []是更难的工作,但性能提升可能很大(记住gcc可能也会为你编写memcpys)。

简而言之,ostringstream没有被破坏,但是越接近金属,代码运行得越快。汇编者对某些人来说仍然有优势。

答案 3 :(得分:1)

要获得更好的性能,您必须了解您使用的容器的工作方式。在char []数组示例中,预先分配所需大小的数组。在vector和ostringstream示例中,随着对象的增长,您迫使对象重复分配和重新分配并可能多次复制数据。

使用std :: vector,可以通过将矢量的大小初始化为最终大小来轻松解决,就像使用char数组一样;相反,你通过调整为零而不公平地削弱了性能!这不是一个公平的比较。

关于ostringstream,不可能预先分配空间,我建议使用它是不合适的。该类具有比简单char数组更大的实用程序,但如果您不需要该实用程序,则不要使用它,因为您将在任何情况下支付开销。相反,它应该用于它的好处 - 将数据格式化为字符串。 C ++提供了各种各样的容器,而ostringstram是最不合适的容器。

在vector和ostringstream的情况下,你可以获得缓冲区溢出的保护,你不会得到一个char数组,并且这种保护不是免费的。