28

これにより、最終的に使用可能なメモリがすべて消費され、プロセスが強制終了されます。タグを「小さい」タグに変更しようとしましたscheduleが、違いはありませんでした。

何が間違っているのですか / この大きなファイルを で処理するにはどうすればよいiterparse()ですか?

import lxml.etree

for schedule in lxml.etree.iterparse('really-big-file.xml', tag='schedule'):
    print "why does this consume all my memory?"

私はそれを簡単に切り刻んで小さな塊に加工することができますが、それは私が望むよりも醜いです.

4

3 に答える 3

33

ファイル全体を反復するとiterparse、ツリーが構築され、要素は解放されません。これを行う利点は、要素がその親が誰であるかを覚えていることであり、祖先要素を参照する XPath を形成できます。欠点は、多くのメモリを消費する可能性があることです。

解析中にメモリを解放するには、Liza Daly のfast_iter:

def fast_iter(context, func, *args, **kwargs):
    """
    http://lxml.de/parsing.html#modifying-the-tree
    Based on Liza Daly's fast_iter
    http://www.ibm.com/developerworks/xml/library/x-hiperfparse/
    See also http://effbot.org/zone/element-iterparse.htm
    """
    for event, elem in context:
        func(elem, *args, **kwargs)
        # It's safe to call clear() here because no descendants will be
        # accessed
        elem.clear()
        # Also eliminate now-empty references from the root node to elem
        for ancestor in elem.xpath('ancestor-or-self::*'):
            while ancestor.getprevious() is not None:
                del ancestor.getparent()[0]
    del context

次のように使用できます。

def process_element(elem):
    print "why does this consume all my memory?"

context = lxml.etree.iterparse('really-big-file.xml', tag='schedule', events=('end',))
fast_iter(context, process_element)

上記の元になった記事を強くお勧めします。fast_iter大きな XML ファイルを扱っている場合は特に興味深いでしょう。

fast_iter上に示したものは、記事に示したもののわずかに変更されたバージョンです。これは、以前の先祖の削除についてより積極的であるため、より多くのメモリを節約できます。ここに、違いを示すスクリプトがあります。

于 2012-08-28T14:06:48.097 に答える
6

http://effbot.org/zone/element-iterparse.htmから直接コピー

iterparse は parse と同様にツリーを構築しますが、解析中にツリーの一部を安全に再配置または削除できることに注意してください。たとえば、大きなファイルを解析するには、要素を処理したらすぐに削除できます。

for event, elem in iterparse(source):
    if elem.tag == "record":
        ... process record elements ...
        elem.clear()

上記のパターンには 1 つの欠点があります。ルート要素はクリアされないため、多くの空の子要素を持つ単一の要素になってしまいます。ファイルが大きいだけでなく巨大な場合、これが問題になる可能性があります。これを回避するには、ルート要素を手に入れる必要があります。これを行う最も簡単な方法は、開始イベントを有効にして、最初の要素への参照を変数に保存することです。

# get an iterable
context = iterparse(source, events=("start", "end"))

# turn it into an iterator
context = iter(context)

# get the root element
event, root = context.next()

for event, elem in context:
    if event == "end" and elem.tag == "record":
        ... process record elements ...
        root.clear()
于 2012-08-28T14:12:11.847 に答える