Понимание Ruby и буферизации ввода-вывода ОС


Как работает буферизация ввода-вывода в Ruby? Как часто данные сбрасываются в базовый поток при использовании классов IO и File? Как это соотносится с буферизацией ОС? Что нужно сделать, чтобы гарантировать, что данные были записаны на диск, прежде чем уверенно считывать их обратно для обработки?

2 29

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: закрывает Ruby IO и записывает отложенные данные в ОС. Заметьте, что это не означает fsync(). Документация POSIX на close() говорит, что это не гарантирует физической записи данных в файл. Поэтому вам нужно использовать явный вызов fsync() для этого.

Вывод: flush и / или close должно быть достаточно для кэширования файла, чтобы он мог быть полностью прочитан другим процессом или операция. Чтобы получить файл полностью на физический носитель с уверенностью, вам нужно вызвать IO.fsync.

Другие связанные методы:

  • IO.syswrite: обходим рубиновые внутренние буферы и делаем прямую ОС write. Если вы используете это, то не смешивайте его с IO.read/write.
  • IO.sysread: то же, что и выше, но для чтения.

Руби делает ее внутренней буферизации на верхней части операционной системы. Когда вы делаете файл.flush Ruby очищает свой внутренний буфер. Чтобы убедиться, что файл записан на диск, вам нужно сделать файл.fsync. Но в конце концов вы не можете быть уверены, что файл записан на диск в любом случае, это зависит от операционной системы, контроллера жесткого диска и жесткого диска.