Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么lxml.etree.iterparse()会占用我所有的内存?_Python_Xml_Memory_Lxml_Iterparse - Fatal编程技术网

Python 为什么lxml.etree.iterparse()会占用我所有的内存?

Python 为什么lxml.etree.iterparse()会占用我所有的内存?,python,xml,memory,lxml,iterparse,Python,Xml,Memory,Lxml,Iterparse,这最终会消耗我所有的可用内存,然后进程被终止。我尝试过将标签从schedule更改为“较小的”标签,但没有任何区别 我做错了什么/如何使用iterparse()处理这个大文件 我可以很容易地将它切碎,并将其处理成更小的块,但这比我想要的更难看。当iterparse在整个文件上迭代时,会生成一棵树,并且不会释放任何元素。这样做的好处是,元素记住其父元素是谁,并且您可以形成引用祖先元素的XPath。缺点是它会消耗大量内存 为了在解析时释放一些内存,请使用Liza Daly的fast\u iter:

这最终会消耗我所有的可用内存,然后进程被终止。我尝试过将标签从
schedule
更改为“较小的”标签,但没有任何区别

我做错了什么/如何使用
iterparse()
处理这个大文件


我可以很容易地将它切碎,并将其处理成更小的块,但这比我想要的更难看。

iterparse
在整个文件上迭代时,会生成一棵树,并且不会释放任何元素。这样做的好处是,元素记住其父元素是谁,并且您可以形成引用祖先元素的XPath。缺点是它会消耗大量内存

为了在解析时释放一些内存,请使用Liza Daly的
fast\u 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\u iter
的基础;如果您处理的是大型XML文件,那么您应该特别感兴趣

上面介绍的
fast\u iter
是对所示版本的稍微修改 在文章中。这是一个更积极的关于删除以前的祖先, 这样可以节省更多内存。这表明 差异。

直接从

注意,iterparse仍然构建一个树,就像parse一样,但是您可以在解析时安全地重新排列或删除树的一部分。例如,要解析大型文件,您可以在处理完元素后立即删除它们:

for event, elem in iterparse(source):
    if elem.tag == "record":
        ... process record elements ...
        elem.clear()
上述模式有一个缺点;它不会清除根元素,因此您将得到一个包含大量空子元素的元素。如果您的文件很大,而不仅仅是很大,这可能是一个问题。要解决这个问题,您需要着手处理根元素。最简单的方法是启用开始事件,并保存对变量中第一个元素的引用:

# 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()

这对我来说非常有效:

def destroy_tree(tree):
    root = tree.getroot()

    node_tracker = {root: [0, None]}

    for node in root.iterdescendants():
        parent = node.getparent()
        node_tracker[node] = [node_tracker[parent][0] + 1, parent]

    node_tracker = sorted([(depth, parent, child) for child, (depth, parent)
                           in node_tracker.items()], key=lambda x: x[0], reverse=True)

    for _, parent, child in node_tracker:
        if parent is None:
            break
        parent.remove(child)

    del tree

谢谢您的解决方案和我刚才添加的解决方案似乎都起到了作用,我很好奇您和其他人认为哪种解决方案更好。你有什么想法吗?原来你的解决方案有效,但解决方案没有(它仍然吞噬了我所有的记忆)谢谢!这是一个真正有效的版本。Liza Daly、effbot和lxml官方文档的版本并没有为我节省太多内存。请注意,
context.next()
在Python 3中变成了
next(context)
def destroy_tree(tree):
    root = tree.getroot()

    node_tracker = {root: [0, None]}

    for node in root.iterdescendants():
        parent = node.getparent()
        node_tracker[node] = [node_tracker[parent][0] + 1, parent]

    node_tracker = sorted([(depth, parent, child) for child, (depth, parent)
                           in node_tracker.items()], key=lambda x: x[0], reverse=True)

    for _, parent, child in node_tracker:
        if parent is None:
            break
        parent.remove(child)

    del tree