大量のピクルスデータを少しずつディスクに書き込む処理を試みています。サンプル コードは次のとおりです。
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、オブジェクト用に独自のシリアル化/逆シリアル化メソッドを作成するなど)。