なぜピクルスは記憶を食べるのか?質問する

なぜピクルスは記憶を食べるのか?質問する

大量のピクルスデータを少しずつディスクに書き込む処理を試みています。サンプル コードは次のとおりです。

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 3Dパーティモジュールで取得したメモリプロファイリングの結果を添付します。メモリプロファイラ:

   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()

ループの実行中に、メモリ使用量が異常に増加します。これを解消するにはどうすればよいでしょうか? 何かご意見はありますか?

入力データの量が増加すると、この追加データのサイズは入力よりもはるかに大きくなる可能性があります (更新: 実際のタスクでは 300 MB 以上になります)

さらに幅広い質問ですが、Python で大量の IO データを適切に処理するにはどのような方法があるのでしょうか?

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

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() だと思っていましたが)

ベストアンサー1

Pickle は大量の RAM を消費します。ここで説明を参照してください。http://www.shocksolution.com/2010/01/storing-large-numpy-arrays-on-disk-python-pickle-vs-hdf5adsf/

Pickle はなぜこれほど多くのメモリを消費するのでしょうか?その理由は、HDF がバイナリ データ パイプであるのに対し、Pickle はオブジェクト シリアル化プロトコルだからです。Pickle は実際には、オブジェクトを一連のオペコードに変換してディスクに書き込む単純な仮想マシン (VM) で構成されています。何かをアンピクルするには、VM がオペコードを読み取って解釈し、オブジェクトを再構築します。このアプローチの欠点は、VM がディスクに書き込む前に、オブジェクトの完全なコピーをメモリ内に構築する必要があることです。

Pickle は、ほとんどの場合メモリ消費がそれほど問題にならないため、小規模なユースケースやテストに最適です。

大量のファイルや大きなファイルをダンプしてロードする必要がある集中的な作業の場合は、データを保存する別の方法を検討する必要があります (例: hdf、オブジェクト用に独自のシリアル化/逆シリアル化メソッドを作成するなど)。

おすすめ記事