xml.etree.ElementTree的iterparse()仍然占用大量内存?
我一直在尝试使用iterparse来减少处理大型XML文档时脚本的内存占用。这里有个例子。我写了一个简单的脚本,用来读取TMX文件,并将其拆分成一个或多个输出文件,确保每个文件的大小不超过用户指定的大小。尽管我使用了iterparse,当我把一个886MB的文件拆分成100MB的文件时,脚本却占用了所有可用的内存(在我8MB的内存中,使用了6.5MB,速度变得非常慢)。
我是不是做错了什么?为什么内存使用量会这么高呢?
#! /usr/bin/python
# -*- coding: utf-8 -*-
import argparse
import codecs
from xml.etree.ElementTree import iterparse, tostring
from sys import getsizeof
def startNewOutfile(infile, i, root, header):
out = open(infile.replace('tmx', str(i) + '.tmx'), 'w')
print >>out, '<?xml version="1.0" encoding="UTF-8"?>'
print >>out, '<!DOCTYPE tmx SYSTEM "tmx14.dtd">'
print >>out, roottxt
print >>out, headertxt
print >>out, '<body>'
return out
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-m', '--maxsize', dest='maxsize', required=True, type=float, help='max size (in MB) of output files')
parser.add_argument(dest='infile', help='.tmx file to be split')
args = parser.parse_args()
maxsize = args.maxsize * 1024 * 1024
nodes = iter(iterparse(args.infile, events=['start','end']))
_, root = next(nodes)
_, header = next(nodes)
roottxt = tostring(root).strip()
headertxt = tostring(header).strip()
i = 1
curr_size = getsizeof(roottxt) + getsizeof(headertxt)
out = startNewOutfile(args.infile, i, roottxt, headertxt)
for event, node in nodes:
if event =='end' and node.tag == 'tu':
nodetxt = tostring(node, encoding='utf-8').strip()
curr_size += getsizeof(nodetxt)
print >>out, nodetxt
if curr_size > maxsize:
curr_size = getsizeof(roottxt) + getsizeof(headertxt)
print >>out, '</body>'
print >>out, '</tmx>'
out.close()
i += 1
out = startNewOutfile(args.infile, i, roottxt, headertxt)
root.clear()
print >>out, '</body>'
print >>out, '</tmx>'
out.close()
1 个回答
6
在一个相关的问题中找到了答案:为什么elementtree.ElementTree.iterparse占用了这么多内存?
我们不仅需要在每次循环中使用root.clear(),还需要在每次迭代中使用node.clear()。因为我们同时处理开始和结束事件,所以要小心不要过早地移除节点:
for e, node in nodes:
if e == 'end' and node.tag == 'tu':
nodetxt = tostring(node, encoding='utf-8').strip()
curr_size += getsizeof(nodetxt)
print >>out, nodetxt
node.clear()
if curr_size > maxsize:
curr_size = getsizeof(roottxt) + getsizeof(headertxt)
print >>out, '</body>'
print >>out, '</tmx>'
out.close()
i += 1
out = startNewOutfile(args.infile, i, roottxt, headertxt)
root.clear()