2012-01-08 74 views
3

我加載在Python腳本12個XML文件(30-80MB每個):與multiprocessing.Pool內存泄露甚至收盤後()

import xml.etree.ElementTree as ET 
files = ['1.xml', '2.xml', ..., '11.xml', '12.xml'] 
trees = [ET.parse(f) for f in files] 

這需要大約50秒的運行。我會跑了幾次,所以我想我會嘗試多以加快其速度:

import multiprocessing  
trees = [None] * len(files) 

def _parse_(i): 
    return (i, ET.parse(files[i])) 

def _save_((i, tree)): 
    trees[i] = tree 

def concurrent_parse(): 
    pool = multiprocessing.Pool() 
    for i in range(len(files)): 
     pool.apply_async(func=_parse_, args=(i,), callback=_save_) 
    pool.close() 
    pool.join() 

這現在運行在30多歲,這是一個很好的改善。但是,我正在從shell運行所有這些,然後交互式地處理數據。在第一個非併發版本完成之後,Python的內存使用率降至1.73GB。併發之後,內存使用量爲2.57GB。

我是使用多處理器的新手,所以請原諒我,如果我錯過了一些基本的東西。但是使用Pool之後失去內存的所有其他問題都指向我正在執行的close()失敗。

PS - 如果這是一種非常愚蠢的方式來加載12個XML文件,請隨時這麼說。

+1

我明白這個問題是關於'multiprocessing',它對我很感興趣(upvoted和訂閱)。但是如果可以的話,請考慮使用'lxml.etree'。我有4個生成的測試文件,每個20 MB。測試結果'lxml/xml'(沒有多重處理):時間 - 1.47/27.95秒;內存 - 411/640 MB。 – reclosedev 2012-01-08 14:29:28

回答

2

我不確定這實際上是一個泄漏,並行實現將需要更多的內存來同時保存所有文件。然後python可能會刪除對象,但不會將內存返回到操作系統,這將看起來像使用更多的內存比現有的對象所需的內存。
那麼如果你多次運行concurrent_parse()會發生什麼?如果內存使用量不變,那麼這不是泄漏。如果內存在每次運行後都上升,那麼這是一個問題,您可能需要查看此線程以獲取有關跟蹤泄漏的信息 - Python memory leaks

+0

這是一個吸引人的解釋,但我並不完全相信這些文件是由單獨的Python進程同時保存的,因此解析中使用的內存應該返回到操作系統。 重新運行concurrent_parse()將我的機器停下來(我給它約10分鐘),因爲內存最大化,它開始分頁所有內容。如果我重新運行它,但只有2-4個文件,那麼內存似乎穩定在2GB左右。但是,重新運行4-6個文件有時可以正常工作,其他時間會達到內存限制。 無論哪種方式,'multiprocessing'可能不是我期待的魔法彈! – 2012-01-09 09:48:21

+0

您是否將所有樹都重置爲None?正如我已經發現的,這很重要,因爲子進程從主進程中獲取對象的副本,所以如果您的樹有大量數據乘以進程數量。經過一番實驗後,只要運行之間的樹重置(至少在CentOS 5上使用python 2.7),重複運行concurrent_parse()後,內存看起來沒有增加。我猜想使用多進程時增加的內存使用量是由於IPC序列化造成的。 – user1013341 2012-01-10 17:14:05

+0

嗯,我明白你的意思。我認爲你的答案可能是正確的,因爲它不是內存泄漏。但是我並不完全滿意爲什麼當所有的實例拷貝進入不同的進程時,原始進程爲什麼最終會使用額外的700MB內存。無論哪種方式,我都會放棄它,因爲Python垃圾系統超出了問題的範圍。謝謝! – 2012-01-12 21:30:02