我正在计算将文本打印到标准输出的各种方法之间的差异。我正在使用cout
和printf
测试ostringstream
,\n
和std::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();
}
这是我的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
以下是我运行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
这些结果是一致的。
答案 0 :(得分:14)
std::endl
触发流的刷新,这会减慢打印速度。见http://en.cppreference.com/w/cpp/io/manip/endl
除非您真的希望刷新流,否则通常建议不要使用std::endl
。如果这对您来说非常重要,取决于您的使用案例。
关于为什么flush
即使在ostringstream上也没有性能影响(不应该发生刷新):似乎需要一个实现来至少构造sentry对象。那些需要检查good
的{{1}}和tie
。应该能够优化对ostream
的调用。这是基于我对libcpp和libstdc ++的解读。
经过一些阅读后,有趣的问题似乎是这样的:构建哨兵对象真的需要pubsync
的实现吗?如果没有,这似乎是一个“实施质量”问题给我。但我实际上认为它需要,因为即使basic_ostringstream::flush
可以更改为设置basic_stringbug
。
答案 1 :(得分:1)
流上的每个输出操作都有多个步骤:
endl
会在流缓冲区上调用额外的虚函数。我个人认为,与其他操作相比,额外的虚拟函数调用实际上具有相对较小的影响。您也可以通过分析此输出来验证此猜测:
out << "stream" << '\n';
......甚至
out << "stream" << out.widen('\n');
尽管如此,流实现可以应用多种改进来减少检查。当然,这是否完成将取决于实施。
答案 2 :(得分:0)
使用std::endl
等同于编写
stream << "\n";
stream.flush();
除非您确实想要触发刷新和/或不关心输出性能,否则请勿使用std::endl
。
此外,不要担心不同平台上的不同行结尾,您的实现会将"\n"
转换为适合您平台的行结尾。