Я узнал, что по умолчанию I/O в программах буферизуется, то есть они обслуживаются из временного хранилища в запрашивающую программу.
Я понимаю, что буферизация улучшает производительность ввода-вывода (возможно, путем сокращения системных вызовов). Я видел примеры отключения буферизации, например, setvbuf
в C. В чем разница между двумя режимами и когда нужно использовать другую?
Буферизованный и небуферизованный IO
Ответ 1
Вы хотите получать небуферизованный вывод, когда хотите убедиться, что вывод был записан до продолжения. Одним из примеров является стандартная ошибка в библиотеке времени выполнения 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 |
+---------------------------------------+
Ответ 2
Вам нужен небуферизованный вывод, когда у вас уже есть большая последовательность байтов, готовая для записи на диск, и вы хотите избежать дополнительной копии во второй буфер в середине.
Буферизованные выходные потоки будут накапливать результаты записи в промежуточный буфер, отправляя его в файловую систему ОС только тогда, когда накоплено достаточно данных (или запрошен flush()
). Это уменьшает количество вызовов файловой системы. Поскольку вызовы файловой системы могут быть дорогими на большинстве платформ (по сравнению с короткими memcpy
), буферизованный вывод является чистым выигрышем при выполнении большого количества небольших операций записи. Небуферизованный вывод обычно лучше, когда у вас уже есть большие буферы для отправки - копирование в промежуточный буфер не приведет к дальнейшему сокращению количества вызовов ОС и добавит дополнительную работу.
Небуферизованный вывод не имеет никакого отношения к обеспечению того, что ваши данные попадают на диск; эта функциональность обеспечивается flush()
и работает как с буферизованными, так и с небуферизованными потоками. Записи буферизованного ввода-вывода не гарантируют, что данные достигли физического диска - файловая система ОС может хранить копию ваших данных неограниченное время, никогда не записывая ее на диск, если она этого захочет. Требуется только зафиксировать его на диск, когда вы вызываете flush()
. (Обратите внимание, что close()
позвонит flush()
от вашего имени).