mmap () против read () - PullRequest
       4

mmap () против read ()

12 голосов
/ 08 апреля 2011

Я пишу массовый редактор тегов ID3 ​​на C. Теги ID3 обычно находятся в начале файла, закодированного в формате mp3, хотя старые теги (версия 1) находятся в конце. Приложение предназначено для приема каталога и списка идентификаторов фреймов из командной строки, а затем повторяет структуру каталогов, обновляя все найденные теги ID3. Пользователь может дополнительно удалить все старые теги (версия 1). Другой вариант - просто отобразить текущие теги без обновления. Каталог может содержать 2 файла или 2 миллиона. Если пользователь хочет обновить файлы, я планировал загрузить весь файл в память, выполнить обновления, а затем сохранить его (файл также можно переименовать). Однако, если пользователь хочет печатать только текущие теги ID3, загрузка всего файла кажется чрезмерной. Ведь файл может быть 200мб.

Я прочитал эту ветку, которая была проницательной - mmap () против блоков чтения

Итак, мой вопрос: какой самый эффективный способ сделать это - read (), mmap () или какая-то комбинация? Идеи дизайна приветствуются.

Edit: Насколько я понимаю, mmap, по сути, делегирует загрузку файла в память, в подсистему виртуальной памяти. Мне кажется, что VMM был бы высоко оптимизирован на большинстве систем, так как это критично для производительности системы.

Ответы [ 4 ]

16 голосов
/ 08 апреля 2011

Это действительно зависит от того, что вы пытаетесь сделать. Если все, что вам нужно сделать, это перейти к известному смещению и прочитать маленький тег, read() может быть быстрее (mmap() должен сделать довольно сложный внутренний учет). Однако, если вы планируете скопировать все 200 МБ MP3 или отсканировать его на наличие какого-либо тега, который может появиться с неизвестным смещением, то mmap(), вероятно, более быстрый подход.

Например, если вам нужно сдвинуть весь файл на несколько сотен байтов, чтобы вставить тег ID3, одним из простых подходов было бы расширить файл с помощью ftruncate(), отобразить файл, а затем memmove() Содержание немного вниз. Это, однако, уничтожит файл, если ваша программа потерпит крах во время работы. Вы также можете скопировать содержимое файла в новый файл - это еще одно место, где действительно работает mmap (); Вы можете просто mmap() старый файл, а затем скопировать все его данные в новый файл одним write().

Короче говоря, mmap() замечательно, если вы выполняете большое количество операций ввода-вывода с точки зрения общего количества переданных байтов; Это связано с тем, что это уменьшает количество необходимых копий и может значительно уменьшить количество записей ядра, необходимых для чтения кэшированных данных. Однако для mmap() требуется как минимум две поездки в ядро ​​(три, если вы очистите отображение, когда закончите!), И выполняет некоторые сложные внутренние учеты в ядре, поэтому фиксированные накладные расходы могут быть высокими.

read(), с другой стороны, включает в себя дополнительное копирование из памяти в память и, таким образом, может быть неэффективным для больших операций ввода-вывода, но является простым, и поэтому фиксированные накладные расходы являются относительно низкими. Короче говоря, используйте mmap() для больших объемных операций ввода-вывода и read() или pread() для одноразовых небольших операций ввода-вывода.

6 голосов
/ 08 апреля 2011

Не беспокойтесь о mmap, если ваш код не связан с процессором, особенно из-за большого количества небольших операций чтения и записи. mmap может звучать хорошо, но это не удивительно, почему не все используют эту альтернативу , похоже,

Учитывая, что вы рекурсивно обращаетесь к потенциально большим структурам каталогов, узким местом будет ввод-вывод каталогов и параллелизм. mmap не поможет.

Update0

При прочтении ссылки на вопрос можно найти ответ, подтверждающий мой опыт:

3 голосов
/ 08 апреля 2011

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

Как уже упоминалось, если вы обрабатываете много данных на диске, я/ O, вероятно, будет доминировать в вашей обработке в любом случае.mmap может быть быстрее, чем чтение, но для разумных реализаций он, вероятно, не намного быстрее, особенно на сегодняшнем оборудовании, которое постоянно становится все быстрее и быстрее, в то время как накопители на дисках застряли со скоростью 7200 и 10000 об / мин в течение многих лет.

Итак, используйте mmap и сделайте ваш код простым и аккуратным.

1 голос
/ 08 апреля 2011

Я не знаю, находятся ли стандартные функции POSIX внутри того, что вам разрешено или вы будете использовать для разработки, но подумайте об этих двух функциях:

int ftruncate(int fildes, off_t length);
int truncate(const char *path, off_t length);

, определенных в unistd.h, которые могутиспользоваться для усечения файла до указанной длины.Таким образом, вы могли бы легко

  • найти, где начинается кадр тегов ID3 ​​(не знаю, сможете ли вы легко вычислить его, просто прочитав заголовок файла MP3, но я предполагаю, что да)
  • сохранить смещение
  • закрыть файл
  • обрезать файл с помощью предоставленной функции
  • открыть файл в двоичном режиме и добавить новые теги

Я не уверен насчет производительности, вы должны протестировать этот метод, но он должен загружать гораздо меньше вещей в оперативной памяти, обеспечивая при этом разумный способ сделать это.

...