这最终消耗了我的所有可用内存,然后进程被杀死。 我试图更改标签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?"
我可以很容易地切开它,并在较小的块处理它,但是这是丑陋的,比我想。
作为iterparse
在整个文件迭代树建并没有元素被释放。 这样做的优点是元素记住他们的父母是谁,你可以形成参考祖先元素的XPath。 其缺点是,它会占用大量的内存。
为了释放为你解析一些内存,使用丽莎达利的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
上面介绍的是在文章中示出的一个略加修改的版本。 这是一个更积极的关于删除以前的祖先,从而节省更多的内存。 在这里,你会发现一个脚本这表明了差异。
从直接复制http://effbot.org/zone/element-iterparse.htm
需要注意的是iterparse仍然建立一棵树,就像解析,但您可以安全地重新排列或删除部分树的同时解析。 例如,解析大文件,你可以得到,只要你处理他们摆脱元素:
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