简体   繁体   English

为什么将std :: endl与ostringstream一起使用会影响输出速度?

[英]Why does using std::endl with ostringstream affect output speed?

I'm timing the difference between various ways to print text to standard output. 我正在计时将文本打印到标准输出的各种方式之间的差异。 I'm testing cout , printf , and ostringstream using both \\n and std::endl . 我正在同时使用\\nstd::endl测试coutprintfostringstream I expected std::endl to make a difference with cout (and it did), but I didn't expect it to slow down output with ostringstream . 我期望std::endlcout有所不同(的确如此),但我没想到它会降低ostringstream输出速度。 I thought using std::endl would just write a \\n to the stream and it would still only get flushed once. 我以为使用std::endl只会向流中写入\\n ,并且仍然只会被刷新一次。 What's going on here? 这里发生了什么? Here's all my code: 这是我所有的代码:

// 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();
}

And here's my Makefile 这是我的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

Here's what I get when I run make followed by make time 这是我在运行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

These results are consistent. 这些结果是一致的。

std::endl triggers a flush of the stream, which slows down printing a lot. std::endl触发流刷新,这会大大减慢打印速度。 See http://en.cppreference.com/w/cpp/io/manip/endl 参见http://en.cppreference.com/w/cpp/io/manip/endl

It is often recommended to not use std::endl unless you really want the stream to be flushed. 通常建议不要使用std::endl除非您确实希望刷新流。 If this is really important to you, depends on your use case. 如果这对您确实很重要,则取决于您的用例。

Regarding why flush has a performance impact even on a ostringstream (where no flushing should happen): It seems that an implementation is required to at least construct the sentry objects. 关于为什么flush甚至对ostringstream都具有性能影响(不应进行刷新):似乎至少需要构造一个构造哨兵对象的实现。 Those need to check good and tie of the ostream . 那些需要检查goodtie的的ostream The call to pubsync should be able to be optimized out. pubsync的调用应该能够被优化。 This is based on my reading of libcpp and libstdc++. 这是基于我对libcpp和libstdc ++的阅读。

After some more reading the interesting question seems to be this: Is an implementation of basic_ostringstream::flush really required to construct the sentry object? 经过更多阅读之后,有趣的问题似乎是:构造岗哨对象是否真的需要basic_ostringstream::flush的实现? If not, this seems like a "quality of implementation" issues to me. 如果没有,对我来说,这似乎是一个“实施质量”问题。 But I actually think it needs to because even a basic_stringbug can change to have its badbit set. 但是我实际上认为需badbit ,因为即使basic_stringbug也可以更改以设置其badbit

Each output operation on a stream dors multiple steps: 流上的每个输出操作执行多个步骤:

  • It checks if the stream is in good shape. 它检查流是否状况良好。
  • It checks if some other stream needs to flushed. 它检查是否需要刷新其他流。
  • The sequence of characters is produced. 产生字符序列。
  • It checks if there is enough space for the written characters. 它检查是否有足够的空间容纳书写字符。
  • The use of endl calls an extra virtual function on the stream buffer. 使用endl在流缓冲区上调用一个额外的虚函数。

I would personally expect that the extra virtual function call actually has relativly small impact compared to the other operations. 我个人希望与其他操作相比,额外的虚拟函数调用实际上影响相对较小。 You can verify this guess by also profiling this output: 您还可以通过分析以下输出来验证此猜测:

out << "stream" << '\n';

... or even ... 甚至

out << "stream" << out.widen('\n');

That said, there are a number of improvements which a stream implementation can apply to cut down on checks. 也就是说,流实现可以应用许多改进来减少检查。 Whether this is done will depend on the implementation, of course. 当然,是否完成将取决于实现方式。

Using std::endl is equivalent to writing 使用std::endl等效于编写

stream << "\n";
stream.flush();

Don't use std::endl unless you actually want to trigger flushing, and / or don't care about output performance. 除非您确实要触发刷新和/或不在乎输出性能,否则不要使用std::endl

Also, don't worry about different line endings on different platforms, your implementation will translate "\\n" to the line ending appropriate for your platform. 另外,不必担心在不同平台上的行尾,您的实现会将"\\n"转换为适合您平台的行尾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM