19

大量のピクルスデータを小さな断片でディスクに書き込むことに対処しようとしています。サンプルコードは次のとおりです。

from cPickle import *
from gc import collect

PATH = r'd:\test.dat'
@profile
def func(item):
    for e in item:
        f = open(PATH, 'a', 0)
        f.write(dumps(e))
        f.flush()
        f.close()
        del f
        collect()

if __name__ == '__main__':
    k = [x for x in xrange(9999)]
    func(k)

open()とclose()はループ内に配置され、メモリ内のデータの蓄積の考えられる原因を除外します。

問題を説明するために、Pythonサードパーティモジュールmemory_profilerで得られたメモリプロファイリングの結果を添付します。

   Line #    Mem usage  Increment   Line Contents
==============================================
    14                           @profile
    15      9.02 MB    0.00 MB   def func(item):
    16      9.02 MB    0.00 MB       path= r'd:\test.dat'
    17
    18     10.88 MB    1.86 MB       for e in item:
    19     10.88 MB    0.00 MB           f = open(path, 'a', 0)
    20     10.88 MB    0.00 MB           f.write(dumps(e))
    21     10.88 MB    0.00 MB           f.flush()
    22     10.88 MB    0.00 MB           f.close()
    23     10.88 MB    0.00 MB           del f
    24                                   collect()

ループの実行中に、奇妙なメモリ使用量の増加が発生します。どうすればそれを排除できますか?何かご意見は?

入力データの量が増えると、この追加データの量は入力よりもはるかに大きくなる可能性があります(upd:実際のタスクでは300 + Mbを取得します)

そしてもっと広い質問-Pythonで大量のIOデータを適切に処理するためにどのような方法がありますか?

upd: ループ本体だけを残してコードを書き直し、成長が具体的にいつ発生するかを確認します。ここで結果は次のとおりです。

Line #    Mem usage  Increment   Line Contents
==============================================
    14                           @profile
    15      9.00 MB    0.00 MB   def func(item):
    16      9.00 MB    0.00 MB       path= r'd:\test.dat'
    17
    18                               #for e in item:
    19      9.02 MB    0.02 MB       f = open(path, 'a', 0)
    20      9.23 MB    0.21 MB       d = dumps(item)
    21      9.23 MB    0.00 MB       f.write(d)
    22      9.23 MB    0.00 MB       f.flush()
    23      9.23 MB    0.00 MB       f.close()
    24      9.23 MB    0.00 MB       del f
    25      9.23 MB    0.00 MB       collect()

dumps()がメモリを消費しているようです。(実際にはwrite()になると思っていましたが)

4

1 に答える 1