Я рассчитываю разницу между различными способами печати текста на стандартный вывод. Я тестирую 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
Эти результаты согласуются.
std::endl
вызывает сброс потока, что сильно замедляет печать. Увидеть http://en.cppreference.com/w/cpp/io/manip/endl
Часто рекомендуется не использовать std::endl
если вы действительно не хотите, чтобы поток был очищен. Если это действительно важно для вас, зависит от вашего варианта использования.
По поводу почему flush
оказывает влияние на производительность даже в потоке ostring (где не должно происходить сбрасывание): кажется, что реализация требуется, по крайней мере, для создания сторожевых объектов. Те, кто должен проверить good
а также tie
из ostream
, Призыв к pubsync
должен быть в состоянии быть оптимизирован. Это основано на моем чтении libcpp и libstdc ++.
После некоторого прочтения интересный вопрос, как представляется, заключается в следующем: basic_ostringstream::flush
действительно требуется построить часовой объект? Если нет, то мне кажется, что это проблема качества реализации. Но я на самом деле думаю, что это нужно, потому что даже basic_stringbug
может измениться, чтобы его badbit
задавать.
Каждая операция вывода в потоке выполняется в несколько этапов:
endl
вызывает дополнительную виртуальную функцию в буфере потока.Я лично ожидал бы, что дополнительный вызов виртуальной функции на самом деле имеет относительно небольшое влияние по сравнению с другими операциями. Вы можете проверить это предположение, также профилировав этот вывод:
out << "stream" << '\n';
… или даже
out << "stream" << out.widen('\n');
Тем не менее, есть ряд улучшений, которые реализация потока может применить, чтобы сократить проверки. Конечно, будет ли это сделано, зависит от реализации.
С помощью std::endl
эквивалентно письму
stream << "\n";
stream.flush();
Не использовать std::endl
если вы на самом деле не хотите инициировать сброс, и / или не заботитесь о производительности на выходе.
Кроме того, не беспокойтесь о разных концах строк на разных платформах, ваша реализация переведет "\n"
до конца строки, соответствующего вашей платформе.