Буферизованный против небуферизованного ввода-вывода

84

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

Sud03r
источник

Ответы:

127

Вам нужен небуферизованный вывод, когда вы хотите убедиться, что вывод был записан, прежде чем продолжить. Одним из примеров является стандартная ошибка библиотеки времени выполнения 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                |
+---------------------------------------+
Paxdiablo
источник
График замечательный. Стоит упомянуть, что FILEвнутренний буфер объекта (потока) полностью отличается от fgetsнеобходимого параметра буфера. Это просто сбило меня с толку на несколько часов, прежде чем я написал код, чтобы понять это. QAQ
Рик
37

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

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

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

Аарон
источник
flush()Гарантирует ли звонок, что он будет записан на диск? Я думал, что только передал его в буфер диска.
jrdioko
2
Вы должны O_SYNCгарантировать, что пишет.
moshbear 07
Небуферизованный ввод-вывод ks о записи на диск. Следовательно, термин небуферизованный (без промежуточного буфера, но напрямую записываемый на диск) для winapi вы вызываете CreateFile с FILE_FLAG_NO_BUFFERING и FILE_FLAG_WRITE_THROUGH, чтобы гарантировать, что данные идут напрямую, сохраняются после каждой записи. Для некоторых других ОС я не знаю.
Мартин Косицки