Python не хватает памяти для синтаксического анализа XML с использованием cElementTree.iterparse

Упрощенная версия моей функции синтаксического анализа XML находится здесь:

import xml.etree.cElementTree as ET

def analyze(xml):
    it = ET.iterparse(file(xml))
    count = 0

    for (ev, el) in it:
        count += 1

    print('count: {0}'.format(count))

Это приводит к нехватке памяти Python, что не имеет большого смысла. Единственное, что я на самом деле храню, это счетчик, целое число. Почему он это делает:

введите описание изображения здесь

Видите это внезапное падение использования памяти и ЦП в конце? Это эффектный сбой Python. По крайней мере, это дает мне MemoryError (в зависимости от того, что еще я делаю в цикле, это дает мне больше случайных ошибок, таких как IndexError) и трассировку стека вместо segfault. Но почему он рушится?


person Aillyn    schedule 08.10.2011    source источник
comment
stackoverflow.com/questions/1513592/ рекомендует вызывать .clear() для каждого элемента, когда вы закончите с ним, чтобы сэкономить память. Предположительно это работает, потому что в противном случае cElementTree сохраняет в памяти ранее возвращенные значения.   -  person Wooble    schedule 08.10.2011
comment
@Wooble Вы должны опубликовать это как ответ. Успешно справился.   -  person Aillyn    schedule 08.10.2011
comment
Кроме того, у меня был хороший успех с lxml; он имеет идентичную (AFAIK) функциональность, но намного эффективнее по памяти и времени.   -  person user    schedule 08.10.2011
comment
@Oliver lxml превосходит ElementTree, но не cElementTree, когда дело доходит до синтаксического анализа.   -  person Aillyn    schedule 09.10.2011
comment
@Wooble: Во всех трех реализациях ElementTree iterparse() строит дерево. Удаление нежелательных элементов остается на усмотрение вызывающего абонента.   -  person John Machin    schedule 09.10.2011
comment
Просто примечание: эта проблема, похоже, вообще не влияет на память на моем Mac, но заставляет мой сервер Ubuntu кровоточить ОЗУ, как будто это выходит из моды.   -  person Mike Davlantes    schedule 12.06.2020


Ответы (2)


Документация действительно сообщает вам " Разбирает XML-раздел в дерево элементов [выделено мной] постепенно », но не описывает, как избежать сохранения неинтересных элементов (которые могут быть всеми). Об этом говорится в этой статье от effbot.

Я настоятельно рекомендую всем, кто использует .iterparse(), прочитать эту статью Лизы Дейли. Он охватывает как lxml, так и [c] ElementTree.

Предыдущее покрытие SO:

Использование Python Iterparse для больших файлов XML
Может ли Python xml ElementTree анализировать очень большой XML-файл? < br> Каков самый быстрый способ разбирать большие XML-документы в Python?

person John Machin    schedule 08.10.2011
comment
Этот ответ действительно должен включать какой-то пример кода или краткое изложение предоставленных ссылок. - person Richard Herbert; 14.05.2019

Пример кода:

import xml.etree.cElementTree as etree

def getelements(filename_or_file, tag):
    context = iter(etree.iterparse(filename_or_file, events=('start', 'end')))
    _, root = next(context) # get root element
    for event, elem in context:
        if event == 'end' and elem.tag == tag:
            yield elem
            root.clear() # preserve memory
person jfs    schedule 07.11.2012
comment
Разве вы не должны вызывать clear() и на elem? Или вы уверены, что простая очистка корня заставит сборщик мусора также собрать элемент? - person Henrik Heimbuerger; 04.04.2013
comment
@hheimbuerger: root.clear() достаточно. Я не копал глубоко, но использование памяти было небольшим, когда я использовал его для анализа больших файлов xml. - person jfs; 05.04.2013