Я думаю, что преимущество в том, что вы уменьшаете объем копирования данных, необходимый по сравнению с традиционными методами чтения файла.
Если ваше приложение может использовать данные «на месте» в файле с отображением памяти, они могут поступать без копирования; если вы используете системный вызов (например, pread () в Linux), то это обычно включает в себя копирование ядром данных из своих собственных буферов в пространство пользователя. Это дополнительное копирование не только требует времени, но и снижает эффективность кешей ЦП за счет доступа к этой дополнительной копии данных.
Если данные действительно должны быть прочитаны с диска (как при физическом вводе-выводе), тогда ОС все равно должна их прочитать, ошибка страницы, вероятно, не лучше с точки зрения производительности, чем системный вызов, но если они нет (т.е. уже в кеше ОС), теоретически производительность должна быть намного лучше.
С другой стороны, нет асинхронного интерфейса для файлов с отображением в память - если вы пытаетесь получить доступ к странице, которая не отображается, она генерирует ошибку страницы, а затем заставляет поток ждать ввода-вывода.
Очевидным недостатком файлов с отображением памяти является 32-разрядная ОС - у вас может легко закончиться адресное пространство.
Я использовал файл с отображением памяти, чтобы реализовать функцию «автозаполнения», пока пользователь печатает. У меня более 1 миллиона номеров деталей, хранящихся в одном индексном файле. Файл имеет типичную информацию заголовка, но основная часть файла представляет собой гигантский массив записей фиксированного размера, отсортированных по ключевому полю.
Во время выполнения файл отображается в память, преобразуется в массив
C
стиляstruct
, и мы выполняем двоичный поиск, чтобы найти совпадающие номера деталей в соответствии с типом пользователя. На самом деле с диска считываются только несколько страниц памяти файла - какие бы страницы ни были обнаружены во время двоичного поиска.источник
Файлы с отображением памяти могут использоваться либо для замены доступа для чтения / записи, либо для поддержки одновременного совместного использования. Когда вы используете их для одного механизма, вы получаете и другой.
Вместо того, чтобы искать, писать и читать в файле, вы отображаете его в память и просто обращаетесь к битам там, где вы их ожидаете.
Это может быть очень удобно и в зависимости от интерфейса виртуальной памяти может повысить производительность. Повышение производительности может произойти, потому что операционная система теперь может управлять этим бывшим «файловым вводом-выводом» вместе со всем вашим другим программным доступом к памяти и может (теоретически) использовать алгоритмы разбиения на страницы и т. Д., Которые она уже использует для поддержки виртуальная память для остальной части вашей программы. Однако это зависит от качества вашей базовой системы виртуальной памяти. Я слышал анекдоты, в которых говорится, что системы виртуальной памяти Solaris и * BSD могут показать лучшие улучшения производительности, чем система виртуальных машин Linux, но у меня нет эмпирических данных, подтверждающих это. YMMV.
Параллелизм становится очевидным, если учесть возможность того, что несколько процессов используют один и тот же «файл» через отображаемую память. В модели чтения / записи, если два процесса записывают данные в одну и ту же область файла, вы можете быть уверены, что данные одного процесса поступят в файл, перезаписав данные другого процесса. Вы получите одно или другое, но не какое-то странное смешение. Я должен признать, что не уверен, соответствует ли такое поведение каким-либо стандартам, но на это можно в значительной степени положиться. (На самом деле это хороший дополнительный вопрос!)
Напротив, в нанесенном на карту мире представьте себе два процесса, оба «пишущие». Они делают это, создавая «хранилища памяти», что в конечном итоге приводит к тому, что операционная система выгружает данные на диск. Но тем временем можно ожидать перекрывающихся операций записи.
Вот пример. Скажем, у меня есть два процесса, которые записывают 8 байтов со смещением 1024. Процесс 1 записывает «11111111», а процесс 2 записывает «22222222». Если они используют файловый ввод-вывод, то вы можете представить себе, что глубоко внутри O / S есть буфер, полный единиц, и буфер, полный двоек, оба направляются в одно и то же место на диске. Один из них доберется туда первым, а другой - вторым. В этом случае выигрывает второй. Однако , если я использую файловый подход с отображением памяти, процесс 1 перейдет в хранилище памяти размером 4 байта, за которым следует другое хранилище памяти из 4 байтов (предположим, что это не максимальный размер хранилища памяти). Процесс 2 будет делать то же самое. В зависимости от того, когда выполняются процессы, вы можете ожидать увидеть любое из следующего:
Решением является использование явного взаимного исключения, что, вероятно, в любом случае является хорошей идеей. В любом случае, вы вроде бы полагались на то, что операционная система сделает «правильные вещи» при чтении / записи файлового ввода-вывода.
Классифицирующим примитивом взаимного исключения является мьютекс. Для файлов с отображением памяти я бы посоветовал вам взглянуть на мьютекс с отображением в память, доступный с помощью, например, pthread_mutex_init ().
Редактируйте с одной хитростью: когда вы используете сопоставленные файлы, существует соблазн встроить указатели на данные в файле, в самом файле (подумайте, что связанный список хранится в сопоставленном файле). Вы не хотите этого делать, поскольку файл может отображаться по разным абсолютным адресам в разное время или в разных процессах. Вместо этого используйте смещения в сопоставленном файле.
источник
Параллелизм будет проблемой. Произвольный доступ проще. Производительность от хорошей до отличной. Удобство использования. Не так хорошо. Портативность - не ахти.
Я использовал их в системе Sun давным-давно, и это мои мысли.
источник