我想在OS X(10.8.2)上使用lxml(3.2.0)解析Python(2.7.2)的1.6 GB XML文件。因为我已经读过有关内存消耗的潜在问题,我已经在其中使用了fast_iter,但是在主循环之后,它会占用大约8 GB的RAM,即使它没有保留实际XML文件中的任何数据
from lxml import etree
def fast_iter(context, func, *args, **kwargs):
# http://www.ibm.com/developerworks/xml/library/x-hiperfparse/
# Author: Liza Daly
for event, elem in context:
func(elem, *args, **kwargs)
elem.clear()
while elem.getprevious() is not None:
del elem.getparent()[0]
del context
def process_element(elem):
pass
context = etree.iterparse("sachsen-latest.osm", tag="node", events=("end", ))
fast_iter(context, process_element)
我不明白,为什么会出现如此大规模的泄漏,因为fast_iter()
中的元素和整个上下文被删除,而目前我甚至都没有处理XML数据。
有什么想法吗?
答案 0 :(得分:3)
问题在于etree.iterparse()
的行为。你会认为它只为每个node
元素使用内存,但事实证明它仍然将所有其他元素保留在内存中。由于你没有清除它们,因此内存最终会爆炸,特别是在解析.osm(OpenStreetMaps)文件并寻找节点时,稍后会有更多内容。
我找到的解决方案不是捕获node
标签,而是捕获所有标签:
context = etree.iterparse(open(filename,'r'),events=('end',))
然后清除所有标签,但只解析您感兴趣的标签:
for (event,elem) in progress.bar(context):
if elem.tag == 'node':
# do things here
elem.clear()
while elem.getprevious() is not None:
del elem.getparent()[0]
del context
请记住,它可能会删除您感兴趣的其他元素,因此请务必在需要时添加更多ifs。例如(这是.osm特定的)tags
嵌套在nodes
if elem.tag == 'tag':
continue
if elem.tag == 'node':
for tag in elem.iterchildren():
# do stuff
以后内存爆炸的原因非常有趣,.osm文件organized的方式是nodes
先来,然后ways
然后是relations
。因此,您的代码在开头就可以正常使用节点,然后在etree
遍历其余元素时填充内存。