Мне было интересно, каков наиболее эффективный способ вывода новой строки на консоль. Объясните, пожалуйста, почему один метод более эффективен. Эффективен с точки зрения производительности.

Например:

cout << endl;
cout << "\n";
puts("");
printf("\n");

Мотивация для этого вопроса заключается в том, что я нахожу свои самописные циклы с выводами, и мне нужно вывести новую строку после всех итераций цикла. Я пытаюсь найти наиболее эффективный способ сделать это, если все остальное не имеет значения. Это предположение, что все остальное не имеет значения, вероятно, неверно.

c++
9
Harrison Tran 13 Май 2016 в 22:33

7 ответов

Лучший ответ

Ответ на этот вопрос действительно «смотря по обстоятельствам».

По отдельности - если все, что вы измеряете, - это производительность записи символа '\n' на стандартное устройство вывода, не настраивая устройство, не меняя буферизацию, тогда будет сложно превзойти такие параметры, как

 putchar('\n');
 fputchar('\n', stdout);

 std::cout.put('\n');

Проблема в том, что это не дает многого - все, что он делает (при условии, что вывод выводится на экран или видимое окно приложения), это перемещает курсор вниз по экрану и перемещает предыдущий вывод вверх. Не совсем развлекательный или ценный опыт для пользователя вашей программы. Так что вы не будете делать это изолированно.

Но что влияет на производительность (как бы вы это ни измеряли), если мы не выводим символы новой строки изолированно? Посмотрим;

  • Вывод stdout (или std::cout) по умолчанию буферизируется. Чтобы вывод был видимым, можно отключить буферизацию или код периодически очищать буфер. Также можно использовать stderr (или std::cerr), поскольку он не буферизуется по умолчанию - при условии, что stderr также направляется на консоль и вывод на него имеет те же характеристики производительности, что и stdout.
  • stdout и std::cout формально синхронизируются по умолчанию (например, поиск std::ios_base::sync_with_stdio), чтобы разрешить смешивание вывода для stdout и std::cout (то же самое для {{X5 }} и std::cerr)
  • Если ваш код выводит больше, чем набор символов новой строки, существует обработка (доступ или чтение данных, на которых основан вывод, любыми способами) для создания этих других выводов, обработка их функциями вывода и т. Д.
  • Существуют разные показатели эффективности и, следовательно, разные средства повышения эффективности в зависимости от каждого из них. Например, могут быть циклы ЦП, общее время вывода вывода на консоль, использование памяти и т. Д.
  • Консоль может быть физическим экраном, это может быть окно, созданное приложением (например, размещенное в X, windows). На производительность будет влиять выбор оборудования, реализация подсистем оконного / графического интерфейса, операционной системы и т. Д.

Вышеупомянутое - всего лишь выбор, но существует множество факторов, которые определяют, что можно считать более или менее производительным.

3
Peter 15 Мар 2019 в 12:29

putchar('\n') - самый простой и, наверное, самый быстрый. cout и printf со строкой "\n" работают со строкой с завершающим нулем, и это медленнее, потому что вы обрабатываете 2 байта (0A 00). Кстати, возврат каретки равен \r = 13 (0x0D). Код \n - перевод строки (LF).

11
i486 13 Май 2016 в 19:34

Вы не указываете, требуете ли вы, чтобы обновление экрана было немедленным или отложенным до следующего сброса. Следовательно:

Если вы используете iostream io:

cout.put('\n');

Если вы используете stdio io:

std::putchar('\n');
6
Richard Hodges 13 Май 2016 в 22:03

На самом деле это зависит от реализации ОС / компилятора.

Самый эффективный способ вывода символа новой строки '\n' с наименьшими побочными эффектами - использовать std::ostream::write() (а для некоторых систем требуется, чтобы std::ostream был открыт в режим std::ios_base::binary):

static const char newline = '\n';
std::cout.write(&newline,sizeof(newline));
4
πάντα ῥεῖ 13 Май 2016 в 20:18

В Ubuntu 15.10, g ++ v5.2.1 (и более старые версии vxWorks и OSE)

Легко показать, что

std::cout << std::endl;

Помещает новый строчный символ в выходной буфер, а затем сбрасывает буфер на устройство.

Но

std::cout << "\n";

Помещает новый строчный символ в выходной буфер и не выводит на устройство. В будущем потребуются некоторые действия для запуска вывода символа новой строки в буфере на устройство.

Два таких действия:

std::cout << std::flush;  // will output the buffer'd new line char

std::cout << std::endl;   // will output 2 new line chars

Есть также несколько других действий, которые могут вызвать сброс буферизации std :: cout.


#include <unistd.h>  // for Linux
void msDelay (int ms) { usleep(ms * 1000); }

int main(int, char**)
{
   std::cout << "with endl and no delay " << std::endl;

   std::cout << "with newline and 3 sec delay " << std::flush << "\n";
   msDelay(3000);

   std::cout << std::endl << " 2 newlines";
   return(0);
}

И, согласно комментарию того, кто знает (извините, я не знаю, как скопировать здесь его имя), есть исключения для некоторых сред.

3
2785528 13 Май 2016 в 20:15

Я бы предложил использовать:

std::cout << '\n';  /* Use std::ios_base::sync_with_stdio(false) if applicable */

Или

fputc('\n', stdout);

Включите оптимизацию, и пусть компилятор решит, как лучше всего выполнить эту тривиальную работу.

2
Mohit Jain 20 Май 2016 в 11:38

Что ж, если вы хотите изменить строку, я бы хотел добавить самый простой и наиболее распространенный способ, который использует (endl), который имеет добавленную привилегию очистки потока, в отличие от cout << '\n'; сам по себе.

Примере:

     cout << "So i want a new line" << endl;
     cout << "Here is your new line";

Выход:

       So i want a new line
       Here is your new line

Это можно сделать для любого количества новых строк. Позвольте мне показать пример с двумя новыми строчками, это обязательно развеет все ваши сомнения,

Примере:

         cout << "This is the first line" << endl;
         cout << "This is the second line" << endl;
         cout << "This is the third line";

Выход:

   This is the first line
   This is the second line
   This is the third line

Последняя строка будет закрыта точкой с запятой, поскольку перевод строки не требуется. (endl) также может быть цепочкой, если это необходимо, например, cout << endl << endl; будет допустимой последовательностью.

1
Centixel 19 Ноя 2020 в 03:20