为什么使用带有ostringstream的std :: endl会影响输出速度?

gsi*_*011 9 c++ performance flush stringstream ostream

我正在计算将文本打印到标准输出的各种方法之间的差异.我正在测试cout,printfostringstream使用\nstd::endl.我希望std::endl能有所作为cout(并且确实如此),但我没想到它会减慢输出速度ostringstream.我以为使用std::endl只会写一个\n流,它仍然只会被刷新一次.这里发生了什么?这是我的所有代码:

// cout.cpp
#include <iostream>

using namespace std;

int main() {
  for (int i = 0; i < 10000000; i++) {
    cout << "Hello World!\n";
  }
  return 0;
}

// printf.cpp
#include <stdio.h>

int main() {
  for (int i = 0; i < 10000000; i++) {
    printf("Hello World!\n");
  }
  return 0;
}

// stream.cpp
#include <iostream>
#include <sstream>

using namespace std;

int main () {
  ostringstream ss;
  for (int i = 0; i < 10000000; i++) {
    ss << "stream" << endl;
  }
  cout << ss.str();
}

// streamn.cpp
#include <iostream>
#include <sstream>

using namespace std;

int main () {
  ostringstream ss;
  for (int i = 0; i < 10000000; i++) {
    ss << "stream\n";
  }
  cout << ss.str();
}
Run Code Online (Sandbox Code Playgroud)

这是我的Makefile

SHELL:=/bin/bash

all: cout.cpp printf.cpp
    g++ cout.cpp -o cout.out
    g++ printf.cpp -o printf.out
    g++ stream.cpp -o stream.out
    g++ streamn.cpp -o streamn.out
time:
    time ./cout.out > output.txt
    time ./printf.out > output.txt
    time ./stream.out > output.txt
    time ./streamn.out > output.txt
Run Code Online (Sandbox Code Playgroud)

这是我跑步make后得到的make time

time ./cout.out > output.txt

real    0m1.771s
user    0m0.616s
sys 0m0.148s
time ./printf.out > output.txt

real    0m2.411s
user    0m0.392s
sys 0m0.172s
time ./stream.out > output.txt

real    0m2.048s
user    0m0.632s
sys 0m0.220s
time ./streamn.out > output.txt

real    0m1.742s
user    0m0.404s
sys 0m0.200s
Run Code Online (Sandbox Code Playgroud)

这些结果是一致的.

pmr*_*pmr 14

std::endl触发流的刷新,这会减慢打印速度.见http://en.cppreference.com/w/cpp/io/manip/endl

std::endl除非您真的想要刷新流,否则通常建议不要使用它.如果这对您来说非常重要,取决于您的使用案例.

关于为什么flush即使在ostringstream上也没有性能影响(不应该发生刷新):似乎需要一个实现来至少构造sentry对象.那些需要检查goodtieostream.pubsync应该能够优化调用.这是基于我对libcpp和libstdc ++的阅读.

经过一些阅读后,有趣的问题似乎是这样的:basic_ostringstream::flush构建哨兵对象真的需要一个实现吗?如果没有,这似乎是一个"实施质量"问题给我.但实际上我认为它需要,因为即使是一个basic_stringbug可以改变它的badbit设置.

  • 我实际上知道这一点,但我不知道它会影响stringstream的性能.刷新cout意味着输出缓冲区中的任何内容输出,刷新stringstream是什么意思?文本被刷新到什么输出? (2认同)
  • @ gsingh2011这就是我的想法.但是``basic_ostringstream`实际上附加了`basic_stringbuf`,并且需要构造`flush`文档中提到的哨兵. (2认同)