Буферизованный и небуферизованный ввод-вывод - PullRequest
67 голосов
/ 20 сентября 2009

Я узнал, что по умолчанию ввод / вывод в программах буферизуется, т. Е. Они передаются из временного хранилища запрашивающей программе. Я понимаю, что буферизация улучшает производительность ввода-вывода (возможно, за счет сокращения системных вызовов). Я видел примеры отключения буферизации, например setvbuf в C. В чем разница между двумя режимами и когда один из них должен использоваться поверх другого?

Ответы [ 2 ]

105 голосов
/ 20 сентября 2009

Вы хотите небуферизованный вывод всякий раз, когда хотите убедиться, что вывод записан перед продолжением. Одним из примеров является стандартная ошибка в библиотеке времени выполнения C - по умолчанию она обычно не буферизируется. Так как ошибки (надеюсь) нечасты, вы хотите знать о них немедленно. С другой стороны, стандартный вывод буферизуется просто потому, что предполагается, что через него будет проходить гораздо больше данных.

Другим примером является библиотека журналов. Если ваши сообщения журнала хранятся в буферах вашего процесса, а ваш процесс сбрасывает ядро, есть очень хороший шанс, что вывод никогда не будет записан.

Кроме того, минимизируются не только системные вызовы, но и дисковый ввод-вывод. Допустим, программа читает файл по одному байту за раз. При небуферизованном вводе вы будете выходить на (относительно очень медленный) диск для каждого байта, даже если в любом случае он, вероятно, должен прочитать весь блок (у самого оборудования диска могут быть буферы, но вы все равно обращаетесь к контроллеру диска). который будет медленнее, чем доступ в памяти).

При буферизации весь блок считывается в буфер сразу, после чего отдельные байты доставляются вам из (в памяти, невероятно быстрой) области буфера.

Имейте в виду, что буферизация может принимать различные формы, например, в следующем примере:

+-------------------+-------------------+
| Process A         | Process B         |
+-------------------+-------------------+
| C runtime library | C runtime library | C RTL buffers
+-------------------+-------------------+
|               OS caches               | Operating system buffers
+---------------------------------------+
|      Disk controller hardware cache   | Disk hardware buffers
+---------------------------------------+
|                   Disk                |
+---------------------------------------+
28 голосов
/ 19 февраля 2011

Требуется небуферизованный вывод, когда у вас уже есть большая последовательность байтов, готовая для записи на диск, и вы хотите избежать дополнительной копии во второй буфер в середине.

Буферизованные выходные потоки будут накапливать результаты записи в промежуточный буфер, отправляя его в файловую систему ОС только тогда, когда накоплено достаточно данных (или запрашивается flush()). Это уменьшает количество вызовов файловой системы. Поскольку вызовы файловой системы могут быть дорогими на большинстве платформ (по сравнению с короткими memcpy), буферизованный вывод является чистым выигрышем при выполнении большого количества небольших операций записи. Небуферизованный вывод, как правило, лучше, когда у вас уже есть большие буферы для отправки - копирование в промежуточный буфер не уменьшит количество вызовов ОС в дальнейшем и приведет к дополнительной работе.

Небуферизованный вывод не имеет ничего , связанного с обеспечением того, что ваши данные достигают диска; эта функциональность обеспечивается flush() и работает как с буферизованными, так и с небуферизованными потоками. Записи буферизованного ввода-вывода не гарантируют, что данные достигли физического диска - файловая система ОС может хранить копию ваших данных неограниченное время, никогда не записывая ее на диск, если она этого захочет. Требуется только зафиксировать его на диск, когда вы вызываете flush(). (Обратите внимание, что close() будет звонить flush() от вашего имени).

...