Ubuntu9.04で実行されているPython2.6.2[GCC4.3.3]を使用しています。Pythonスクリプトを使用して、大きなデータファイル(〜1GB、> 300万行)を1行ずつ読み取る必要があります。
以下の方法を試してみましたが、非常に大きなメモリスペース(〜3GB)を使用していることがわかりました
for line in open('datafile','r').readlines():
process(line)
また、
for line in file(datafile):
process(line)
大きなファイルを1行ずつロードするより良い方法はありますか?
- a)ファイルがメモリに一度にロードできる最大行数を明示的に言及することによって?または
- b)サイズのチャンク、たとえば1024バイトでロードすることにより、チャンクの最後の行が切り捨てられることなく完全にロードされる場合はどうなりますか?
いくつかの提案は私が上で述べた方法を与え、すでに試しました、私はこれを処理するためのより良い方法があるかどうかを見ようとしています。私の検索は今のところ実り多いものではありません。私はあなたの助けに感謝します。
p / sを使用してメモリプロファイリングを実行しましたが、使用Heapy
しているPythonコードでメモリリークは見つかりませんでした。
2012年8月20日16:41(GMT + 1)更新
JF Sebastian、mgilson、およびIamChuckBによって提案された両方のアプローチを試しました(データファイルは変数です)
with open(datafile) as f:
for line in f:
process(line)
また、
import fileinput
for line in fileinput.input([datafile]):
process(line)
不思議なことに、どちらも最大3GBのメモリを使用します。このテストでの私のデータファイルのサイズは、21,181,079行で構成される765.2MBです。3GBで安定する前に、メモリが時間とともに増加する(約40〜80MBステップ)のがわかります。
基本的な疑問、使用後にラインをフラッシュする必要がありますか?
これをよりよく理解するために、Heapyを使用してメモリプロファイリングを行いました。
レベル1プロファイリング
Partition of a set of 36043 objects. Total size = 5307704 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 15934 44 1301016 25 1301016 25 str
1 50 0 628400 12 1929416 36 dict of __main__.NodeStatistics
2 7584 21 620936 12 2550352 48 tuple
3 781 2 590776 11 3141128 59 dict (no owner)
4 90 0 278640 5 3419768 64 dict of module
5 2132 6 255840 5 3675608 69 types.CodeType
6 2059 6 247080 5 3922688 74 function
7 1716 5 245408 5 4168096 79 list
8 244 1 218512 4 4386608 83 type
9 224 1 213632 4 4600240 87 dict of type
<104 more rows. Type e.g. '_.more' to view.>
================================================== ==========
レベル1-インデックス0のレベル2プロファイリング
Partition of a set of 15934 objects. Total size = 1301016 bytes.
Index Count % Size % Cumulative % Referred Via:
0 2132 13 274232 21 274232 21 '.co_code'
1 2132 13 189832 15 464064 36 '.co_filename'
2 2024 13 114120 9 578184 44 '.co_lnotab'
3 247 2 110672 9 688856 53 "['__doc__']"
4 347 2 92456 7 781312 60 '.func_doc', '[0]'
5 448 3 27152 2 808464 62 '[1]'
6 260 2 15040 1 823504 63 '[2]'
7 201 1 11696 1 835200 64 '[3]'
8 188 1 11080 1 846280 65 '[0]'
9 157 1 8904 1 855184 66 '[4]'
<4717 more rows. Type e.g. '_.more' to view.>
レベル1のレベル2プロファイリング-インデックス1
Partition of a set of 50 objects. Total size = 628400 bytes.
Index Count % Size % Cumulative % Referred Via:
0 50 100 628400 100 628400 100 '.__dict__'
レベル1-インデックス2のレベル2プロファイリング
Partition of a set of 7584 objects. Total size = 620936 bytes.
Index Count % Size % Cumulative % Referred Via:
0 1995 26 188160 30 188160 30 '.co_names'
1 2096 28 171072 28 359232 58 '.co_varnames'
2 2078 27 157608 25 516840 83 '.co_consts'
3 261 3 21616 3 538456 87 '.__mro__'
4 331 4 21488 3 559944 90 '.__bases__'
5 296 4 20216 3 580160 93 '.func_defaults'
6 55 1 3952 1 584112 94 '.co_freevars'
7 47 1 3456 1 587568 95 '.co_cellvars'
8 35 0 2560 0 590128 95 '[0]'
9 27 0 1952 0 592080 95 '.keys()[0]'
<189 more rows. Type e.g. '_.more' to view.>
レベル1-インデックス3のレベル2プロファイリング
Partition of a set of 781 objects. Total size = 590776 bytes.
Index Count % Size % Cumulative % Referred Via:
0 1 0 98584 17 98584 17 "['locale_alias']"
1 29 4 35768 6 134352 23 '[180]'
2 28 4 34720 6 169072 29 '[90]'
3 30 4 34512 6 203584 34 '[270]'
4 27 3 33672 6 237256 40 '[0]'
5 25 3 26968 5 264224 45 "['data']"
6 1 0 24856 4 289080 49 "['windows_locale']"
7 64 8 20224 3 309304 52 "['inters']"
8 64 8 17920 3 327224 55 "['galog']"
9 64 8 17920 3 345144 58 "['salog']"
<84 more rows. Type e.g. '_.more' to view.>
================================================== ==========
レベル2-インデックス0、レベル1-インデックス0のレベル3プロファイリング
Partition of a set of 2132 objects. Total size = 274232 bytes.
Index Count % Size % Cumulative % Referred Via:
0 2132 100 274232 100 274232 100 '.co_code'
レベル2-インデックス0、レベル1-インデックス1のレベル3プロファイリング
Partition of a set of 50 objects. Total size = 628400 bytes.
Index Count % Size % Cumulative % Referred Via:
0 50 100 628400 100 628400 100 '.__dict__'
レベル2-インデックス0、レベル1-インデックス2のレベル3プロファイリング
Partition of a set of 1995 objects. Total size = 188160 bytes.
Index Count % Size % Cumulative % Referred Via:
0 1995 100 188160 100 188160 100 '.co_names'
レベル2-インデックス0、レベル1-インデックス3のレベル3プロファイリング
Partition of a set of 1 object. Total size = 98584 bytes.
Index Count % Size % Cumulative % Referred Via:
0 1 100 98584 100 98584 100 "['locale_alias']"
まだこれをトラブルシューティングします。
あなたが以前にこれに直面したことがあるなら、私と共有してください。
ご協力いただきありがとうございます。
2012年8月21日01:55(GMT + 1)更新
- mgilson、プロセス関数は、ネットワークシミュレータ2(NS2)トレースファイルを後処理するために使用されます。トレースファイルの一部の行は、以下のように共有されます。ワイヤレスネットワークのパフォーマンスを学習するために、Pythonスクリプトで多数のオブジェクト、カウンター、タプル、および辞書を使用しています。
s 1.231932886 _25_ AGT --- 0 exp 10 [0 0 0 0 Y Y] ------- [25:0 0:0 32 0 0] s 1.232087886 _25_ MAC --- 0 ARP 86 [0 ffffffff 67 806 Y Y] ------- [REQUEST 103/25 0/0] r 1.232776108 _42_ MAC --- 0 ARP 28 [0 ffffffff 67 806 Y Y] ------- [REQUEST 103/25 0/0] r 1.232776625 _34_ MAC --- 0 ARP 28 [0 ffffffff 67 806 Y Y] ------- [REQUEST 103/25 0/0] r 1.232776633 _9_ MAC --- 0 ARP 28 [0 ffffffff 67 806 Y Y] ------- [REQUEST 103/25 0/0] r 1.232776658 _0_ MAC --- 0 ARP 28 [0 ffffffff 67 806 Y Y] ------- [REQUEST 103/25 0/0] r 1.232856942 _35_ MAC --- 0 ARP 28 [0 ffffffff 64 806 Y Y] ------- [REQUEST 100/25 0/0] s 1.232871658 _0_ MAC --- 0 ARP 86 [13a 67 1 806 Y Y] ------- [REPLY 1/0 103/25] r 1.233096712 _29_ MAC --- 0 ARP 28 [0 ffffffff 66 806 Y Y] ------- [REQUEST 102/25 0/0] r 1.233097047 _4_ MAC --- 0 ARP 28 [0 ffffffff 66 806 Y Y] ------- [REQUEST 102/25 0/0] r 1.233097050 _26_ MAC --- 0 ARP 28 [0 ffffffff 66 806 Y Y] ------- [REQUEST 102/25 0/0] r 1.233097051 _1_ MAC --- 0 ARP 28 [0 ffffffff 66 806 Y Y] ------- [REQUEST 102/25 0/0] r 1.233109522 _25_ MAC --- 0 ARP 28 [13a 67 1 806 Y Y] ------- [REPLY 1/0 103/25] s 1.233119522 _25_ MAC --- 0 ACK 38 [0 1 67 0 Y Y] r 1.233236204 _17_ MAC --- 0 ARP 28 [0 ffffffff 65 806 Y Y] ------- [REQUEST 101/25 0/0] r 1.233236463 _20_ MAC --- 0 ARP 28 [0 ffffffff 65 806 Y Y] ------- [REQUEST 101/25 0/0] D 1.233236694 _18_ MAC COL 0 ARP 86 [0 ffffffff 65 806 67 1] ------- [REQUEST 101/25 0/0]
Heapyを使用して3レベルのプロファイリングを行う目的は、メモリの多くを消費しているオブジェクトを絞り込むのに役立つことです。ご覧のとおり、残念ながら、一般的すぎるため、どれを具体的に調整する必要があるのかわかりませんでした。例" dictof main .NodeStatistics"には36043(0.1%)オブジェクトのうち50オブジェクトしかありませんが、スクリプトの実行に使用される合計メモリの12%を占めているので、どの特定の辞書を見つけることができません。調べる必要があります。
以下のようにDavidEykの提案を実装してみました(スニペット)。500,000行ごとに手動でガベージコレクションを試みました。
import gc for i,line in enumerate(file(datafile)): if (i%500000==0): print '-----------This is line number', i collected = gc.collect() print "Garbage collector: collected %d objects." % (collected)
残念ながら、メモリ使用量はまだ3GBであり、出力(スニペット)は次のとおりです。
-----------This is line number 0
Garbage collector: collected 0 objects.
-----------This is line number 500000
Garbage collector: collected 0 objects.
- martineauの提案を実装すると、メモリ使用量が以前の3GBから22MBになっていることがわかります。達成するのを楽しみにしていたこと。奇妙なことは以下です、
以前と同じメモリプロファイリングを行いましたが、
レベル1プロファイリング
Partition of a set of 35474 objects. Total size = 5273376 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 15889 45 1283640 24 1283640 24 str
1 50 0 628400 12 1912040 36 dict of __main__.NodeStatistics
2 7559 21 617496 12 2529536 48 tuple
3 781 2 589240 11 3118776 59 dict (no owner)
4 90 0 278640 5 3397416 64 dict of module
5 2132 6 255840 5 3653256 69 types.CodeType
6 2059 6 247080 5 3900336 74 function
7 1716 5 245408 5 4145744 79 list
8 244 1 218512 4 4364256 83 type
9 224 1 213632 4 4577888 87 dict of type
<104 more rows. Type e.g. '_.more' to view.>
以前のメモリプロファイリング出力を上記と比較すると、strは45オブジェクト(17376バイト)を削減し、tupleは25オブジェクト(3440バイト)を削減し、dict(所有者なし)はオブジェクトを変更しませんが、メモリサイズを1536バイト削減しました。main .NodeStatisticsのdictを含め、他のすべてのオブジェクトは同じです。オブジェクトの総数は35474です。オブジェクトのわずかな削減(0.2%)により、99.3%のメモリ節約が実現しました(3GBから22MB)。非常に奇妙な。
ご存知のように、メモリ不足が発生している場所はわかっていますが、出血の原因を特定することはできます。
これを調査し続けます。
すべてのポインタに感謝します。私は専門家ではないので、この機会を利用してPythonについて多くを学ぶことができます。私を助けるためにかかったあなたの時間を感謝します。
2012年8月23日更新00:01(GMT + 1)-解決済み
martineauの提案に従って、最小限のコードを使用してデバッグを続けました。プロセス関数にコードを追加し、メモリの出血を観察し始めました。
以下のようにクラスを追加すると、メモリが出血し始めます。
class PacketStatistics(object): def __init__(self): self.event_id = 0 self.event_source = 0 self.event_dest = 0 ...
136個のカウンターを持つ3つのクラスを使用しています。
この問題について友人のグスタボ・カルネイロと話し合ったところ、彼はdictの代わりにスロットを使用することを提案しました。
クラスを以下のように変換しました。
class PacketStatistics(object): __slots__ = ('event_id', 'event_source', 'event_dest',...) def __init__(self): self.event_id = 0 self.event_source = 0 self.event_dest = 0 ...
3つのクラスすべてを変換すると、以前の3GBのメモリ使用量は504MBになりました。なんと80%のメモリ使用量節約!!
以下は、dictからslotへの変換後のメモリプロファイリングです。
Partition of a set of 36157 objects. Total size = 4758960 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 15966 44 1304424 27 1304424 27 str 1 7592 21 624776 13 1929200 41 tuple 2 780 2 587424 12 2516624 53 dict (no owner) 3 90 0 278640 6 2795264 59 dict of module 4 2132 6 255840 5 3051104 64 types.CodeType 5 2059 6 247080 5 3298184 69 function 6 1715 5 245336 5 3543520 74 list 7 225 1 232344 5 3775864 79 dict of type 8 244 1 223952 5 3999816 84 type 9 166 0 190096 4 4189912 88 dict of class <101 more rows. Type e.g. '_.more' to view.>
はdict of __main__.NodeStatistics
もうトップ10に入っていません。
結果に満足しており、この問題を解決できてうれしいです。
ご指導ありがとうございます。本当に感謝しています。
rgdsサラバナンK