4

クリーンにシャットダウンできるようにする必要があるサーバースクリプトがあります。通常のステートメントをテストしているときに、通常の方法では機能しないtry..exceptことに気付きました。Ctrl-C通常、私はこのような長時間実行されるタスクをラップします

try:
    ...
except KeyboardInterrupt:
    #close the script cleanly here

そのため、でタスクを正常にシャットダウンできますCtrl-C。私はこれまでこれで問題に遭遇したことはありませんがCtrl-C、この特定のスクリプトが実行されているときにヒットすると、スクリプトはキャッチせずに終了しますCtrl-C

初期バージョンはProcessfromを使用して実装されましmultiprocessingた。Threadfromを使用してスクリプトを書き直しましたthreadingが、同じ問題があります。threading私はこれまで何度も使用したことがありますが、multiprocessing図書館は初めてです。Ctrl-Cいずれにせよ、私はこれまでこの行動を経験したことがありません。

通常、私は常に番兵などを実装してQueuesThreadインスタンスを整然と閉じますが、このスクリプトは応答なしで終了します。

signal.SIGINT最後に、このようにオーバーライドしてみました

def handler(signal, frame):
    print 'Ctrl+C'

signal.signal(signal.SIGINT, handler)
...

ここCtrl+Cで実際にキャッチされましたが、ハンドラーは実行されず、何も出力されません。

threading/multiprocessingアスペクトに加えて、スクリプトの一部にはC++ SWIGオブジェクトが含まれています。それがそれと関係があるのか​​どうかはわかりません。OSXLionでPython2.7.2を実行しています。

だから、いくつかの質問:

  1. 何が起きてる?
  2. どうすればこれをデバッグできますか?
  3. 根本的な原因を理解するために何を学ぶ必要がありますか?

注意:スクリプトの内部は独自のものであるため、コード例を示すことはできません。ただし、これを自分でデバッグできるように、ポインターを喜んで受け取ります。私は、誰かが私を正しい方向に向けることができるかどうかを理解するのに十分な経験を積んでいます。

編集:C++ SWIG奇妙な動作の原因を確認するためにインポートなどをコメントアウトし始め、ライブラリのインポートに絞り込みました。ライブラリをインポートする理由がC++ SWIG「盗む」という考えはありCtrl-Cますか?私は有罪の図書館の著者ではありませんが、私のSWIGの経験は限られているので、どこから始めればよいのかよくわかりません...

編集2: Windowsマシンで同じスクリプトを試したところ、Windows7ではCtrl-C期待どおりにキャッチされました。私は実際にはOSXの部分を気にするつもりはありません、とにかくスクリプトはWindows環境で実行されます。

4

3 に答える 3

4

これは、Pythonがスレッド、シグナル、C呼び出しを管理する方法に関係している可能性があります。

つまり、Ctrl-CはC呼び出しを中断できません。これは、実装では、Pythonスレッドがシグナルを処理する必要があり、スレッドだけでなくメインスレッド(多くの場合、ブロックされ、他のスレッドを待機している)を処理する必要があるためです。

実際、長い操作はすべてをブロックする可能性があります。

このことを考慮:

>>> nums = xrange(100000000)
>>> -1 in nums
False (after  ~ 6.6 seconds)
>>>

ここで、Ctrl-Cを押してみてください(中断できません!)

>>> nums = xrange(100000000)
>>> -1 in nums
^C^C^C   (nothing happens, long pause)
...
KeyboardInterrupt
>>>

Ctrl-Cがスレッド化されたプログラムで機能しない理由は、メインスレッドが中断できないスレッドでブロックされることが多いためです-結合またはロック(たとえば、「待機」、「結合」、または単なる空の「メイン」スレッド。バックグラウンドでPythonが生成されたスレッドに「参加」します)。

シンプルなものを挿入してみてください

while True:
    time.sleep(1)

メインスレッドで。

長時間実行されるC関数を使用している場合は、Cレベルで信号処理を実行してください(フォースがあなたと一緒にいるように!)。

これは主に、このテーマに関するDavidBeazleyのビデオに基づいています。

于 2012-02-04T18:51:08.420 に答える
1

他の何かがKeyboardInteruptをキャッチしてから他の例外を発生させるか、単にNoneを返す可能性があるため、終了します。デバッグに役立つトレースバックを取得する必要があります。トレースバックを確認できるように、stderr出力をキャプチャするか、-iコマンドラインオプションを使用してスクリプトを実行する必要があります。また、他のすべての例外をキャッチするために、別の例外ブロックを追加します。

C++関数呼び出しがCTRL+Cをキャッチしていると思われる場合は、その出力をキャッチしてみてください。C関数が何も返さない場合は、作成者に例外処理や戻りコードなどを追加するように依頼する以外にできることはほとんどありません。

try:
    #Doing something proprietary  ...
    #catch the function call output
    result = yourCFuncCall()

    #raise an exception if it's not what you expected
    if result is None:
        raise ValueError('Unexpected Result')

except KeyboardInterupt:
    print('Must be a CTRL+C')
    return

except:
    print('Unhandled Exception')
    raise
于 2012-02-04T09:03:29.420 に答える
0

atexitはどうですか? http://docs.python.org/library/atexit.html#module-atexit

于 2012-02-04T10:11:15.420 に答える