[英]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
. 我正在同时使用
\\n
和std::endl
测试cout
, printf
和ostringstream
。 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::endl
与cout
有所不同(的确如此),但我没想到它会降低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
. 那些需要检查
good
和tie
的的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: 流上的每个输出操作执行多个步骤:
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.