sen*_*nte 19 python xml memory lxml iterparse
这最终消耗了我所有可用的内存,然后该进程被终止.我已经尝试将标签更改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?"
Run Code Online (Sandbox Code Playgroud)
我可以轻松地将其切割并以较小的块处理它,但这比我想要的更糟糕.
unu*_*tbu 22
由于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
Run Code Online (Sandbox Code Playgroud)
你可以这样使用:
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)
Run Code Online (Sandbox Code Playgroud)
我强烈推荐的文章在其上面fast_iter的基础; 如果您处理大型XML文件,它应该特别有趣.
在fast_iter上面介绍的文章中所示的一个略加修改的版本.这个更加积极地删除以前的祖先,从而节省更多的内存. 在这里,您将找到一个演示差异的脚本.
直接复制自http://effbot.org/zone/element-iterparse.htm
请注意,iterparse 仍然会构建一棵树,就像 parse 一样,但您可以在解析时安全地重新排列或删除树的某些部分。例如,要解析大文件,您可以在处理完元素后立即删除它们:
for event, elem in iterparse(source):
if elem.tag == "record":
... process record elements ...
elem.clear()
Run Code Online (Sandbox Code Playgroud)
上述模式有一个缺点;它不会清除根元素,因此您最终会得到一个带有许多空子元素的单个元素。如果您的文件很大,而不仅仅是很大,这可能是一个问题。要解决此问题,您需要掌握根元素。最简单的方法是启用开始事件,并将对第一个元素的引用保存在变量中:
# 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()
Run Code Online (Sandbox Code Playgroud)