私はいくつかの大きなtxtファイルを扱っています。各ファイルには約8000000行あります。行の短い例を次に示します。
usedfor zipper fasten_coat
usedfor zipper fasten_jacket
usedfor zipper fasten_pant
usedfor your_foot walk
atlocation camera cupboard
atlocation camera drawer
atlocation camera house
relatedto more plenty
それらを辞書に保存するコードは次のとおりです。
dicCSK = collections.defaultdict(list)
for line in finCSK:
line=line.strip('\n')
try:
r, c1, c2 = line.split(" ")
except ValueError:
print line
dicCSK[c1].append(r+" "+c2)
最初のtxtファイルでは問題なく動作しますが、2番目のtxtファイルまで動作すると、MemoryError
というエラーが発生します。
ウィンドウ7 64ビットをpython 2.7 32ビット、Intel i5 CPU、8Gbメモリで使用しています。問題を解決するにはどうすればよいですか?
さらに説明すると、4つの大きなファイルがあり、各ファイルには多くのエンティティの異なる情報が含まれています。たとえば、cat
、その親ノードanimal
、およびその子ノードpersian cat
等々。したがって、私のプログラムは最初に辞書のすべてのtxtファイルを読み取り、次にすべての辞書をスキャンしてcat
とその父と子の情報を見つけます。
最も簡単な解決策:おそらく仮想アドレス空間が不足しています(通常、他の形式のエラーは、MemoryError
を最終的に取得する前に長時間ゆっくり実行することを意味します)。これは、Windows(およびほとんどのOS)の32ビットアプリケーションが2 GBのユーザーモードアドレス空間に制限されているためです(Windowsを調整して3 GBにすることもできますが、それでも低容量です)。 8 GBのRAMがありますが、プログラムは(少なくとも)3/4を使用できません。 Pythonはオブジェクトごとのオーバーヘッド(オブジェクトヘッダー、割り当てアライメントなど)がかなりあります。文字列だけがGB近くのRAMを使用している可能性があります。辞書のオーバーヘッド、プログラムの残り、Pythonの残りなど。メモリ空間が十分に断片化し、辞書を大きくする必要がある場合、再割り当てするのに十分な連続したスペースがなく、MemoryError
。
64ビットバージョンのPython(できれば、他の理由でPython 3にアップグレードすることをお勧めします);より多くのメモリを使用しますが、次に、access to lotより多くのメモリスペース(およびより多くの物理的RAM)もあります)になります。
それだけでは不十分な場合は、sqlite3
データベース(または他のDB)への変換を検討してください。これにより、かなり効率的なルックアップを維持しながら、データがメインメモリに対して大きくなりすぎるとディスクに自然に流出します。
サンプルテキストがすべてのテキストを代表すると仮定すると、私のマシンでは1行で約75バイトを消費します。
In [3]: sys.getsizeof('usedfor zipper fasten_coat')
Out[3]: 75
大まかな計算を行う:
75 bytes * 8,000,000 lines / 1024 / 1024 = ~572 MB
そのため、これらのファイルの1つに文字列を単独で格納するには、約572 MBです。同様の構造とサイズのファイルを追加し始めると、@ ShadowRangerの回答で述べたように、仮想アドレススペースの制限にすぐに近づきます。
pythonをアップグレードできない場合、または缶をたたき出すだけの場合(結局物理メモリが限られている場合)、実際には2つのオプションがあります:結果を書き込む入力ファイルの読み込みと読み込みの間にある一時ファイル、またはデータベースへの結果の書き込み。文字列を集計した後、さらに後処理する必要があるため、データベースへの書き込みが優れたアプローチです。