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