Каковы наиболее эффективные идиомы для потоковой передачи данных с диска с постоянным использованием пространства?

описание проблемы

Мне нужно передавать большие файлы с диска. Предположим, что файлы больше, чем поместится в памяти. Кроме того, предположим, что я выполняю некоторые вычисления с данными, и результат достаточно мал, чтобы поместиться в памяти. В качестве гипотетического примера предположим, что мне нужно вычислить md5sum файла размером 200 ГБ, и мне нужно сделать это с гарантиями того, сколько оперативной памяти будет использовано.

В итоге:

  • Должно быть постоянное пространство
  • Как можно быстрее
  • Предположим, очень большие файлы
  • Результат умещается в памяти

Вопрос

Каковы самые быстрые способы чтения/потока данных из файла с использованием постоянного пространства?

Идеи, которые у меня были

Если бы файл был достаточно мал, чтобы поместиться в памяти, то mmap в системах POSIX был бы очень быстрым, к сожалению, здесь это не так. Есть ли какое-либо преимущество в производительности при использовании mmap с небольшим размером буфера для буферизации последовательных фрагментов файла? Будут ли накладные расходы системных вызовов на перемещение буфера mmap вниз по файлу преобладать над какими-либо преимуществами или мне следует использовать фиксированный буфер, в который я считываю с помощью fread?


person Jason Dagit    schedule 07.12.2009    source источник


Ответы (3)


Я бы не был так уверен, что mmap будет очень быстрым (где очень быстро определяется как значительно быстрее, чем fread).

Раньше Grep использовал mmap, но вернулся к fread. Одной из причин была стабильность (с mmap происходят странные вещи, если файл сжимается во время отображения или возникает ошибка ввода-вывода). На этой странице обсуждается часть истории этого.

Вы можете сравнить производительность на своей системе с опцией --mmap для grep. В моей системе разница в производительности файла размером 200 ГБ незначительна, но у вас результат может отличаться!

Короче говоря, я бы использовал fread с буфером фиксированного размера. Его проще кодировать, легче обрабатывать ошибки, и он почти наверняка будет достаточно быстрым.

person Jeff Foster    schedule 08.12.2009

В зависимости от языка, который вы используете, C-подобный цикл fread(), основанный на файле, для которого вы объявили определенный размер буфера, потребует именно этого размера буфера, ни больше, ни меньше.

Обычно мы выбираем размер буфера от 4 до 128 кбайт, с большими буферами выигрыш невелик.

Если бы производительность была чрезвычайно важна, для относительно небольшого выигрыша (и с риском повторного изобретения чего-либо) можно было бы рассмотреть возможность использования двухпоточной реализации, при которой один поток читает файл в наборе из двух буферов, а другой поток выполняет вычисления последовательно в одном из буферов за раз. Таким образом можно устранить задержки доступа к диску.

person mjv    schedule 07.12.2009

mjv прав. Вы можете использовать двойные буферы и перекрывающийся ввод-вывод. Таким образом, ваш хруст и чтение диска могут происходить одновременно. Затем я профилировал или стекировал хруст, чтобы сделать его как можно быстрее. Если повезет, это будет быстрее, чем ввод-вывод, поэтому вы в конечном итоге запустите ввод-вывод на максимальной скорости без паузы. Затем в дело вступают такие вещи, как фрагментация файлов.

person Mike Dunlavey    schedule 08.12.2009