Pythonで巨大なCSVの処理が突然停止した場合、「killed」とはどういう意味ですか?


89

大きなCSVファイルをインポートし、ファイル内の各単語の出現回数をカウントして、そのカウントを別のCSVファイルにエクスポートするPythonスクリプトがあります。

しかし、何が起こっているのかというと、そのカウント部分が終了してエクスポートが開始されるとKilled、ターミナルに表示されます。

これはメモリの問題ではないと思います(もしそうなら、メモリエラーが発生するのではなく、発生すると思いますKilled)。

プロセスに時間がかかりすぎている可能性がありますか?もしそうなら、私がこれを避けることができるようにタイムアウト期間を延長する方法はありますか?

コードは次のとおりです。

csv.field_size_limit(sys.maxsize)
    counter={}
    with open("/home/alex/Documents/version2/cooccur_list.csv",'rb') as file_name:
        reader=csv.reader(file_name)
        for row in reader:
            if len(row)>1:
                pair=row[0]+' '+row[1]
                if pair in counter:
                    counter[pair]+=1
                else:
                    counter[pair]=1
    print 'finished counting'
    writer = csv.writer(open('/home/alex/Documents/version2/dict.csv', 'wb'))
    for key, value in counter.items():
        writer.writerow([key, value])

そして、印刷Killed後に発生finished countingし、完全なメッセージは次のとおりです。

killed (program exited with code: 137)

6
表示されているエラーメッセージの正確な表現を投稿してください。
ロバートハーベイ

2
「killed」とは、通常、プロセスが終了する原因となったシグナルを受信したことを意味します。この場合、スクリプトと同時に発生しているため、パイプが壊れている可能性が高いため、プロセスは、もう一方の端で閉じられているファイルハンドルからの読み取りまたはファイルハンドルへの書き込みを試みています。
アンドリュークラーク

3
killedメッセージの送信元についての回答ではありませんが、ある種のシステムメモリ制限を超えたことが原因である場合は、最終ループのcounter.iteritems()代わりにを使用して修正できる可能性がありcounter.items()ます。Python 2ではitems、ディクショナリ内のキーと値のリストを返します。これが非常に大きい場合は、大量のメモリが必要になる可能性があります。対照的に、iteritemsは、任意の時点で少量のメモリしか必要としないジェネレータです。
Blckknght 2013年

回答:


101

終了コード137(128 + 9)は、シグナル9(SIGKILL。)を受信したためにプログラムが終了したことを示します。これもkilledメッセージを説明しています。問題は、なぜその信号を受信したのかということです。

最も可能性の高い理由は、プロセスが使用を許可されているシステムリソースの量の制限を超えたことです。OSと構成によっては、開いているファイルが多すぎたり、ファイルシステムスペースが多すぎたりする可能性があります。最も可能性が高いのは、プログラムがメモリを使いすぎていることです。システムは、メモリ割り当てが失敗し始めたときに問題が発生するリスクを冒すのではなく、メモリを使いすぎていたプロセスに強制終了シグナルを送信しました。

以前にコメントしたように、印刷後にメモリ制限に達する可能性がある理由の1つは、最後のループでをfinished counting呼び出すとcounter.items()、辞書のすべてのキーと値を含むリストが割り当てられるためです。辞書に大量のデータがある場合、これは非常に大きなリストになる可能性があります。考えられる解決策counter.iteritems()は、ジェネレーターを使用することです。リスト内のすべてのアイテムを返すのではなく、メモリ使用量を大幅に減らしてアイテムを反復処理できます。

したがって、最後のループとして、これを試すことをお勧めします。

for key, value in counter.iteritems():
    writer.writerow([key, value])

Python 3では、itemsPython2のバージョンと同じオーバーヘッドを持たない「ディクショナリビュー」オブジェクトを返すことに注意してください。これは置き換えiteritemsられるため、後でPythonバージョンをアップグレードすると、ループが元の状態に戻ることになります。


2
正解ですが、辞書自体も多くのメモリを消費します。OPは、ファイルの読み取りと処理を一度に行うのではなく、段階的に行うことを検討する必要があります。
ケビン

24

関係するストレージ領域には、スタックとヒープの2つがあります。スタックはメソッド呼び出しの現在の状態が保持される場所(つまり、ローカル変数と参照)であり、ヒープはオブジェクトが保存される場所です。再帰と記憶

counterヒープ領域のメモリを大量に消費するキーがdictに多すぎるため、PythonランタイムでOutOfMemory例外が発生すると思います。

保存するために、カウンターなどの巨大なオブジェクトを作成しないでください。

1.StackOverflow

作成するローカル変数が多すぎるプログラム。

Python 2.7.9 (default, Mar  1 2015, 12:57:24) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open('stack_overflow.py','w')
>>> f.write('def foo():\n')
>>> for x in xrange(10000000):
...   f.write('\tx%d = %d\n' % (x, x))
... 
>>> f.write('foo()')
>>> f.close()
>>> execfile('stack_overflow.py')
Killed

2.OutOfMemory

巨人を作成するプログラムにdictは、あまりにも多くのキーが含まれています。

>>> f = open('out_of_memory.py','w')
>>> f.write('def foo():\n')
>>> f.write('\tcounter = {}\n')
>>> for x in xrange(10000000):
...   f.write('counter[%d] = %d\n' % (x, x))
... 
>>> f.write('foo()\n')
>>> f.close()
>>> execfile('out_of_memory.py')
Killed

参考文献

2

時間がかかるからといって、何かがプロセスを殺しているのではないかと思います。一般的に、killは、外部からの何かがプロセスを終了したことを意味しますが、この場合はCtrl-Cを押すと、PythonがKeyboardInterrupt例外で終了するため、おそらくそうではありません。また、Pythonでは、それが問題である場合、MemoryError例外が発生します。発生している可能性があるのは、プロセスのクラッシュを引き起こすPythonまたは標準ライブラリコードのバグに遭遇していることです。


クラッシュするバグはSIGKILL、Pythonがraise(SIGKILL)何らかの理由でコードのどこかにある場合を除いて、取得するよりもセグメンテーション違反を引き起こす可能性がはるかに高くなります。
ケビン

1
PythonのバグはSIGKILLを送信しませんでした。
QWR

2

ほとんどの場合、メモリが不足しているため、カーネルがプロセスを強制終了しました。

OOM Killerについて聞いたことがありますか?

これは、CSVファイルからの膨大なデータセットを処理するために開発したスクリプトのログです。

Mar 12 18:20:38 server.com kernel: [63802.396693] Out of memory: Kill process 12216 (python3) score 915 or sacrifice child
Mar 12 18:20:38 server.com kernel: [63802.402542] Killed process 12216 (python3) total-vm:9695784kB, anon-rss:7623168kB, file-rss:4kB, shmem-rss:0kB
Mar 12 18:20:38 server.com kernel: [63803.002121] oom_reaper: reaped process 12216 (python3), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

から取得しました/var/log/syslog

基本的に:

PID 12216が犠牲者として選出されたため(合計VMの+ 9Gbを使用したため)、oom_killerがそれを獲得しました。

これがOOMの振る舞いに関する記事です。


1
+1、明確にするために、プログラムが使用しようとしているRAMの量を理解するために、total-vm、anon-rss、file-rssの値を合計する必要がありますか?また、total-vmは、実際に使用可能なメモリではなく、プログラムが使用している量を示します。申し訳ありませんが、知識が限られています。
momo

1
私の知識は、この文脈でも限られています、@ momo。私はさらなる調査のために少し時間がありませんが、私は役立つかもしれないこの投稿を見つけました:stackoverflow.com/questions/18845857/…。私が言えることは、実際、total-vmは、プロセスによって使用されるメモリの量であるということです。
ivanleoncz

0

VirtualBox新しいUbuntu20.04 LTS内の共有フォルダーからPythonスクリプトを実行しようとしたときに、同じことが起こりました。Killed私自身の個人的なライブラリをロードしている間、Pythonは助けになりました。フォルダをローカルディレクトリに移動すると、問題は解決しました。Killedフォルダを移動するとライブラリが見つからないというメッセージが表示されたため、ライブラリの最初のインポート中に停止が発生したようです。

コンピュータを再起動すると、問題は解決しました。

したがって、プログラムが何らかの共有を超えている場合、またはOSの再起動が必要な一時的な問題である可能性がある場合は、プログラムをローカルディレクトリに移動してみてください。


待って、ホストまたはVMを再起動する必要がありましたか?
cglacet

はい。私の場合、新しいVMを構築していて、この問題が発生したときにPythonをインストールしたばかりでした。再起動後、消えました。私は物事を修正する方法として再起動するのが嫌いなので、デバッグを試みて、ここSOを含め、1時間掘り下げた後、たくさんの時間を費やしました。しかし、結局、私はあきらめて再起動し、プレストしました。なぜそれが機能したのか分かりません。
ティモシーC.クイン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.