Python загружает 2 ГБ текстового файла в память

В Python 2.7, когда я загружаю все данные из текстового файла размером 2,5 ГБ в память для более быстрой обработки следующим образом:

>>> f = open('dump.xml','r')
>>> dump = f.read()

Я получил следующую ошибку:

Python(62813) malloc: *** mmap(size=140521659486208) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError

Почему Python пытался выделить 140521659486208 байт памяти для 2563749237 байтов данных? Как исправить код, чтобы он загружал все байты?

У меня свободно около 3 Гб оперативной памяти. Файл представляет собой XML-дамп Викисловаря.


person pckben    schedule 22.06.2012    source источник
comment
Почему бы вам не разобрать XML линейно без предварительной загрузки исходного кода в память?   -  person Alfe    schedule 22.06.2012
comment
Я попробовал, и это заняло у меня очень много времени. И так как у меня много оперативной памяти, я хочу загрузить все в оперативную память, чтобы сделать это быстрее.   -  person pckben    schedule 22.06.2012
comment
У меня 8 ГБ ОЗУ на моем Mac Pro, я думаю, что это 64-разрядная версия.   -  person pckben    schedule 22.06.2012
comment
Вы пытались вызвать mmap вручную?   -  person joslinm    schedule 22.06.2012
comment
Ух ты. 128 Терабайт? Это амбициозно malloc().   -  person Tim Pietzcker    schedule 22.06.2012
comment
Я очень новичок в Python. Сейчас читаю об этом. Что меня больше всего озадачило, так это то, почему Python хочет выделять около 50 КБ памяти на каждый байт данных? Какая структура данных стоит за строкой f.read()?   -  person pckben    schedule 22.06.2012
comment
Я не думаю, что чтение источника XML в память для его последующего анализа ускорит что-либо. Разбирайте его, пока читаете. Это быстрее.   -  person Alfe    schedule 22.06.2012
comment
Кстати, используйте парсер SAX вместо парсера DOM. В противном случае вам снова потребуются огромные объемы оперативной памяти.   -  person Alfe    schedule 22.06.2012
comment
@Alfe Я пробовал анализировать XML, накапливая строки до полной записи статьи, это заняло у меня вечность. Поэтому я перешел к этому решению, чтобы использовать регулярное выражение finditer() для линейного сопоставления шаблона и вместо этого извлекать интересующие данные. Теперь это заняло у меня больше минуты.   -  person pckben    schedule 22.06.2012
comment
Я предлагаю использовать xml ElementTree вместо SAX. Никому, кроме вас, не понравится ваше решение регулярного выражения.   -  person Acumenus    schedule 22.06.2012
comment
Другие на SO просмотрели этот XML-файл для анализа. Вы можете посмотреть на это.   -  person    schedule 22.06.2012
comment
Спасибо, я знаю об этих ссылках. Я просто пытался отделить заголовок страницы и содержание от дампа для экспериментов позже. ElementTree занял много времени, прежде чем я переключился на решение с регулярными выражениями. Теперь он работает нормально.   -  person pckben    schedule 23.06.2012


Ответы (2)


Если вы используете mmap, вы сможете сразу загрузить весь файл в память.

import mmap

with open('dump.xml', 'rb') as f:
  # Size 0 will read the ENTIRE file into memory!
  m = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) #File is open read-only

  # Proceed with your code here -- note the file is already in memory
  # so "readine" here will be as fast as could be
  data = m.readline()
  while data:
    # Do stuff
    data = m.readline()
person joslinm    schedule 22.06.2012
comment
Я получил mmap.error: [Errno 13] Permission denied за строку с m = mmap.mmap(..), как мне это исправить? - person pckben; 22.06.2012
comment
@pckben Это потому, что файл открыт в режиме только для чтения, и mmap попытается сопоставить чтение-запись: добавьте prot=mmap.PROT_READ в свой вызов mmap.mmap, и все будет в порядке. - person Thomas Orozco; 22.06.2012
comment
Хороший ответ, если вам действительно нужно полностью прочитать содержимое файла. В данном случае я не думаю, что это лучшее решение для ситуации pckben. - person Alfe; 22.06.2012
comment
mmap — отображение памяти файла. Доступ к памяти в выделенном месте вместо этого приведет к доступу к файлу. Буферизирует ли ОС весь файл заранее или только при доступе, это часть конфигурации ;-) - person Alfe; 22.06.2012
comment
@pckben Использование open('myfile', 'rb') открывает файл в режиме только для чтения, но mmap попытается сопоставить его для чтения и записи, что приведет к ошибке. - person Thomas Orozco; 22.06.2012

Погуглив немного, я наткнулся на этот пост на форуме, который кажется решить проблему, которая у вас возникла. Предполагая, что вы используете Mac или Linux на основе кода ошибки, вы можете попробовать реализовать сборку мусора с помощью gc.enable() или gc.collect(), как это предлагается в сообщении на форуме.

person acrognale    schedule 22.06.2012
comment
мой код состоит всего из 2 строк, как указано для загрузки данных в память, другого живого объекта для сборки мусора нет. - person pckben; 22.06.2012