Использование буфера выходного потока в контексте к std :: cout и std :: endl - PullRequest
0 голосов
/ 30 сентября 2018

Я пытаюсь понять, как работает буфер выходного потока.Я не нашел ничего, что объясняет весь процесс написания стандартного вывода в контексте std::cout.Насколько я понимаю, std::cout на самом деле не печатает на стандартном выводе, а записывает содержимое в буфер потока вывода эмулятора терминала.Когда буфер заполнен, эмулятор терминала удаляет содержимое буфера и записывает его на дисплей терминала (стандартный вывод).По моему мнению, это то, что происходит, когда эмулятор терминала выполняет операцию flush.

В случае std::endl в эмулятор терминала делается явный запрос на очистку содержимогобуфер сразу, что вызывает снижение производительности.Это падение вызвано тем, что наша программа потратила время на создание запроса flush к эмулятору терминала и ожидала, пока содержимое буфера будет напечатано на дисплее терминала, прежде чем перейти к следующей строке кода.Без std::endl, std::cout не заботится о том, чтобы печатать содержимое сразу.Это оставляет ответственность за печать на эмуляторе терминала (путем записи содержимого в буфер потока вывода эмулятора терминала).У меня есть несколько сомнений:

(1) Мое понимание того, как эмуляторы терминала отображают текст, запрошенный std::cout, точно?

(2) Запрос flush сделан кОС или эмулятор терминала?

(3) Если мы увеличим размер буфера выходного потока эмулятора терминала, произойдет ли увеличение производительности программы, дополненное заметной задержкой печати содержимого наотображение?

1 Ответ

0 голосов
/ 30 сентября 2018

Нет, ваше понимание неверно.«Эмуляторы терминала» не задействованы, по крайней мере, напрямую.

Выходной буфер находится внутри самого объекта потока (std::cout в данном случае).Существует три возможных способа использования этого буфера, в зависимости от политики буферизации потока:

  • Буферизованный блок: выходные данные сначала сохраняются в буфере.Когда буфер заполнен, он «сбрасывается», то есть его содержимое записывается в базовый (ОС-ориентированный) выходной канал, а буфер очищается.

  • Буферизованная строка: работает как блокбуферизуется, но буфер также сбрасывается всякий раз, когда в него записывается новая строка ('\n').

  • Небуферизованный: выходной буфер не используется.Весь вывод записывается немедленно.

Когда вы открываете файл, поток начинает буферизироваться блоком.std::cerr небуферизован.std::cout - буферизованная строка, если вывод поступает на терминал, а блок буферизован в противном случае.

std::flush немедленно очищает буфер вывода (если есть).

Относительно того, как данные на самом делеНаписано, детали зависят от вашей операционной системы.В системах Unix существует системный вызов с именем write («системный вызов» - это запрос операционной системы на выполнение каких-либо действий).Системные вызовы обычно медленнее, чем обычные вызовы функций;выходной буфер является оптимизацией производительности, потому что вы не хотите вызывать write для каждого символа вывода.Внутренний сбор выходных данных до тех пор, пока у вас не наберется больший пакет текста, означает меньшее количество вызовов write, что означает повышение общей производительности.

Что касается ваших конкретных вопросов:

  1. Нет, эмуляторы терминала не имеют отношения.

  2. ОС.

  3. Буфер находится в объекте потока, а не в эмуляторе терминала.Увеличение размера буфера прекращает давать вам какие-либо преимущества в производительности после некоторого момента.Ваша программа обычно тратит большую часть своего времени на вычисление результатов и выполнение других операций, кроме написания текста в std::cout.

...