5

で大きな xml ファイルを処理していlxml.iterparseます。これはうまく機能しますが、最近私のファイルが非常に大きくなったため、メモリをいっぱいにする iterparse 動作を見つけました。elem次のコードを考えてみましょう。このコードは、1 つの並べ替えに 300000要素、300000 要素と 300000要素を含むファイルを書き込みますother_elem

els = ('<elem><subel1>{0}</subel1><subel2>{0}</subel2><subel3>{0}</subel3><subel4>{0}</subel4><subel5>{0}</subel5><subel6>{0}</subel6></elem>'.format(x) for x in range(300000))
other_els = ('<other_elem><subel1>{0}</subel1><subel2>{0}</subel2><subel3>{0}</subel3><subel4>{0}</subel4><subel5>{0}</subel5><subel6>{0}</subel6></other_elem>'.format(x) for x in range(300000))

with open('/tmp/test.xml', 'w') as fp:
   fp.write('<root>\n')
   fp.write('<elements>\n')
   for el in els:
       fp.write(el+'\n')
   fp.write('</elements>\n')
   fp.write('<other_elements>\n')
   for el in other_els:
       fp.write(el+'\n')
   fp.write('</other_elements>\n')
   fp.write('</root>\n')

elem次に、メモリ使用量を時々出力しながら、以下を使用してのみを解析します(そしてそれらに対しては何もしません)。

from lxml import etree
import psutil
import os

process = psutil.Process(os.getpid())
gen = etree.iterparse('/tmp/test.xml', tag='elem')
elscount = 0
for ac,el in gen:
    elscount += 1
    el.clear()
    if el.getprevious() is not None:
        del(el.getparent()[0])
    if elscount % 10000 == 0:
        print process.get_memory_info().rss/(1024*1024)

print process.get_memory_info().rss/(1024*1024)

出力は最後までメモリ使用量が少ないことを示しており、突然ジャンプします。sを含まないファイルを読み込もうとすると、この動作はなくなりますother_elem。iterparse への引数を省略し、代わりに if コンストラクトを使用してそれをテストする遅い回避策はtag、おそらくel.clear()一致しない要素に対して実行できるため、メモリを解放します。したがって、私の質問はこれを解決する方法ではありませんが、出力する必要のない要素で iterparse がメモリを浪費するのはなぜですか、またはおそらく、ここで何が間違っているのでしょうか?

4

0 に答える 0