Как работает буферизация ввода-вывода в Ruby? Как часто данные сбрасываются в базовый поток при использовании классов IO
и File
? Как это соотносится с буферизацией ОС? Что нужно сделать, чтобы гарантировать, что данные были записаны на диск, прежде чем уверенно прочитать его для обработки?
Понимание буферизации ввода-вывода в Ruby и OS
Ответ 1
Документация Ruby IO не на 100% понятна, как работает эта буферизация, но это то, что вы можете извлечь из документации:
- Ruby IO имеет собственный внутренний буфер
- В дополнение к этому базовая операционная система может или не может дополнительно буферизовать данные.
Соответствующие методы для просмотра:
-
IO.flush
: СбрасываетIO
. Я также посмотрел на источник Ruby, и вызовIO.flush
также вызывает базовую ОСfflush()
. Этого должно быть достаточно для кэширования файла, но он не гарантирует физические данные на диске. -
IO.sync=
: если установлено значениеtrue
, внутренняя буферизация Ruby не выполняется. Все немедленно отправляется в ОС, и для каждой записи вызываетсяfflush()
. -
IO.sync
: возвращает текущую настройку синхронизации (true
илиfalse
). -
IO.fsync
: Сбрасывает как буферы Ruby + вызовыfsync()
в ОС (если он его поддерживает). Это гарантирует полную очистку вплоть до файла физического диска. -
IO.close
: Закрывает RubyIO
и записывает ожидающие данные в ОС. Заметим, что это не означаетfsync()
. Документация POSIX наclose()
говорит, что она НЕ гарантирует, что данные физически записаны в файл. Поэтому вам нужно использовать явный вызовfsync()
для этого.
Заключение: flush
и/или close
должно быть достаточно, чтобы файл был кэширован, чтобы его можно было прочитать полностью другим процессом или операцией. Чтобы получить файл полностью на физическом носителе с уверенностью, вам нужно позвонить IO.fsync
.
Другие связанные методы:
-
IO.syswrite
: обходить внутренние буферы Ruby и делать прямую ОСwrite
. Если вы используете это, не смешивайте его сIO.read/write
. -
IO.sysread
: То же, что и выше, но для чтения.
Ответ 2
Ruby выполняет внутреннюю буферизацию поверх ОС. Когда вы делаете file.flush, Ruby очищает свой внутренний буфер. Чтобы файл записывался на диск, вам необходимо выполнить file.fsync. Но в конце концов вы не можете быть уверены, что файл записывается на диск в любом случае, это зависит от ОС, контроллера hdd и hdd.