Почему Python mmap не работает с большими файлами? - PullRequest
44 голосов
/ 02 ноября 2009

[Изменить: эта проблема относится только к 32-разрядным системам. Если ваш компьютер, ваша ОС и ваша реализация на python 64-битные, то создание больших файлов работает надежно и чрезвычайно эффективно.]

Я пишу модуль, который, помимо прочего, предоставляет побитовый доступ для чтения к файлам. Файлы могут быть большими (сотни ГБ), поэтому я написал простой класс, который позволяет мне обрабатывать файл как строку и скрывает все операции поиска и чтения.

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

Проблема в том, что mmap не работает с большими файлами! Это очень удивительно для меня, так как я думал, что это, пожалуй, самое очевидное приложение. Если размер файла превышает несколько гигабайт, я получаю EnvironmentError: [Errno 12] Cannot allocate memory. Это происходит только с 32-битной сборкой Python, поэтому кажется, что она исчерпывает адресное пространство, но я не могу найти никакой документации по этому вопросу.

Мой код просто

f = open('somelargefile', 'rb')
map = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)

Итак, мой вопрос Я что-то упускаю здесь очевидное? Есть ли способ заставить mmap работать с большими файлами или я должен вернуться к своей наивной оболочке для файлов?


Обновление. Похоже, что у карты Python mmap должны быть те же ограничения, что и у карты POSIX. Чтобы лучше выразить свое недовольство, приведу простой класс, который имеет небольшую часть функциональности mmap.

import os

class Mmap(object):
    def __init__(self, f):
        """Initialise with a file object."""
        self.source = f

    def __getitem__(self, key):
        try:
            # A slice
            self.source.seek(key.start, os.SEEK_SET)
            return self.source.read(key.stop - key.start)
        except AttributeError:
            # single element
            self.source.seek(key, os.SEEK_SET)
            return self.source.read(1)

Это только для чтения и не делает ничего особенного, но я могу сделать это так же, как с mmap:

map2 = Mmap(f)
print map2[0:10]
print map2[10000000000:10000000010]

за исключением того, что нет никаких ограничений на размер файла. Не слишком сложно на самом деле ...

Ответы [ 8 ]

37 голосов
/ 02 ноября 2009

Из IEEE 1003.1:

Функция mmap () должна установить отображение между адресом процесса пространство и файл, общая память объект или [TYM] типизированная память объект.

Ему нужно все виртуальное адресное пространство, потому что это именно то, что mmap() делает .

Тот факт, что на 1018 * не действительно не хватает памяти, не имеет значения - вы не можете отобразить больше адресного пространства, чем у вас есть. Поскольку вы затем берете результат и получаете доступ к нему, как к памяти , как именно вы предлагаете получить доступ к файлу более чем 2 ^ 32 байта? Даже если mmap() не дал сбоя, вы все равно можете прочитать только первые 4 ГБ, прежде чем исчерпаете пространство в 32-разрядном адресном пространстве. Конечно, вы можете mmap() скользящее 32-битное окно поверх файла, но это не обязательно принесет вам какую-либо выгоду, если вы не сможете оптимизировать свой шаблон доступа так, чтобы ограничить количество посещений предыдущих окон.

17 голосов
/ 03 ноября 2009

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

Документация Python не упоминает POSIX mmap, и поэтому, если вы придете к нему как программист Python без особых знаний о POSIX (как я это сделал), тогда проблема с адресным пространством кажется совершенно произвольной и плохо спроектированной!

Спасибо другим авторам за то, что они научили меня истинному значению mmap. К сожалению, никто не предложил лучшую альтернативу моему классу, созданному вручную, для обработки больших файлов как строк, поэтому мне придется придерживаться этого пока. Возможно, я уберу это и сделаю его частью открытого интерфейса моего модуля, когда у меня будет такая возможность.

16 голосов
/ 02 ноября 2009

32-битная программа и операционная система могут адресовать максимум 32 бита памяти, то есть 4 ГБ. Есть и другие факторы, которые делают общую сумму еще меньше; например, Windows резервирует от 0,5 до 2 ГБ для доступа к оборудованию, и, конечно, ваша программа также займет некоторое место.

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

9 голосов
/ 02 ноября 2009

модуль mmap предоставляет все инструменты, которые вам нужны в большом файле, но из-за ограничений, о которых упоминали другие люди, вы не можете отобразить его сразу . Вы можете отобразить кусок хорошего размера сразу, выполнить некоторую обработку, а затем удалить это и сопоставить другой. Ключевыми аргументами для класса mmap являются length и offset, которые в точности соответствуют их звучанию, позволяя отображать length байтов, начиная с байта offset в отображаемом файле. Каждый раз, когда вы хотите прочитать раздел памяти, который находится за пределами отображенного окна, вы должны отобразить в новом окне.

6 голосов
/ 02 ноября 2009

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

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

Это хорошо, но это не карта памяти, это то, что предлагает преимущество более широкого диапазона данных за счет более ограничительного API.

2 голосов
/ 13 декабря 2016

Используйте 64-битный компьютер с 64-битной ОС и 64-битной реализацией Python или избегайте memmap()

memmap() требует аппаратной поддержки процессора, чтобы иметь смысл с большими файлами, большими чем несколько ГиБ.

Он использует MMU ЦП и подсистемы прерываний, чтобы позволить выставлять данные, как если бы они были уже загружены.

MMU - это аппаратное обеспечение, которое будет генерировать прерывание всякий раз, когда осуществляется доступ к адресу, соответствующему данным, не относящимся к физической ОЗУ, и ОС будет обрабатывать прерывание способом, который имеет смысл во время выполнения, поэтому код доступа никогда не узнает (или не нуждается знать), что данные не помещаются в оперативной памяти.

Это упрощает написание вашего кода доступа. Однако, чтобы использовать memmap() таким образом, все задействованное должно обрабатывать 64-битные адреса.

Или же может быть предпочтительнее вообще отказаться от memmap() и самостоятельно управлять памятью.

2 голосов
/ 02 ноября 2009

Вы устанавливаете параметр длины в ноль, что означает карту во всем файле. В 32-битной сборке это будет невозможно, если длина файла превышает 2 ГБ (возможно, 4 ГБ).

1 голос
/ 02 ноября 2009

Вы просите ОС отобразить весь файл в диапазоне памяти. Он не будет прочитан до тех пор, пока вы не вызовете сбои страниц при чтении / записи, но все равно необходимо убедиться, что весь диапазон доступен для вашего процесса, и если этот диапазон слишком велик, возникнут трудности.

...