web-dev-qa-db-ja.com

Pythonスレッドからアプリケーション全体を終了する方法は?

Pythonアプリケーションをそのスレッドの1つから終了するにはどうすればよいですか?sys.exit()は、それが呼び出されたスレッドのみを終了するので、助けにはなりません。

Os.kill()ソリューションはあまりきれいではないので、使用したくありません。

55
linkmaster03

メインスレッドを除くすべてのスレッドがデーモンである場合、最良のアプローチは一般的に thread.interrupt_main() -すべてのスレッドがそれを使用してメインスレッドでKeyboardInterruptを発生させることができます。通常は、メインスレッド(メインスレッドのファイナライザーが呼び出されるなどを含む)から適切にクリーンな終了につながる可能性があります。

もちろん、これによりプロセス全体が生き続けるデーモン以外のスレッドが発生する場合は、Markが推奨するようにos._exitでフォローアップする必要がありますが、最後の手段として(kill -9 ;-)それは物事をかなり荒々しく終了するためです(try/finallyブロック、withブロック、atexit関数などを含むファイナライザーは実行されません)。

50
Alex Martelli

短い答え: _os._exit_ を使用してください。

例付きの長い答え:

DevShedのチュートリアル の単純なスレッドの例をヤンクして少し変更しました:

_import threading, sys, os

theVar = 1

class MyThread ( threading.Thread ):

   def run ( self ):

      global theVar
      print 'This is thread ' + str ( theVar ) + ' speaking.'
      print 'Hello and good bye.'
      theVar = theVar + 1
      if theVar == 4:
          #sys.exit(1)
          os._exit(1)
      print '(done)'

for x in xrange ( 7 ):
   MyThread().start()
_

sys.exit(1)をコメントアウトしたままにすると、3番目のスレッドが出力された後にスクリプトが停止します。 sys.exit(1)を使用してos._exit(1)をコメントアウトすると、3番目のスレッドはnotprint _(done)_を実行します、プログラムは7つのスレッドすべてを実行します。

_os._exit_「通常、fork()の後の子プロセスでのみ使用する必要があります」-そして、別のスレッドが目的に十分に近い。また、そのマニュアルページの_os._exit_の直後に列挙された値がいくつかあり、上記の例で使用したような単純な数値ではなく、_os._exit_の引数として使用する必要があります。

45
Mark Rushakoff

thread.interrupt_main()を使用すると、状況によっては役に立たない場合があります。 KeyboardInterruptsは、現在のコマンドを終了したり、入力行を削除したりするために、コマンドラインアプリケーションでよく使用されます。

加えて、 os._exitは、コード内でfinallyブロックを実行せずにプロセスを即座に強制終了します。これは危険な場合があります(たとえば、ファイルと接続は閉じられません)。

私が見つけた解決策は、カスタム例外を発生させるメインスレッドにシグナルハンドラを登録することです。バックグラウンドスレッドを使用して、シグナルを起動します。

import signal
import os
import threading
import time


class ExitCommand(Exception):
    pass


def signal_handler(signal, frame):
    raise ExitCommand()


def thread_job():
    time.sleep(5)
    os.kill(os.getpid(), signal.SIGUSR1)


signal.signal(signal.SIGUSR1, signal_handler)
threading.Thread(target=thread_job).start()  # thread will fire in 5 seconds
try:
    while True:
        user_input = raw_input('Blocked by raw_input loop ')
        # do something with 'user_input'
except ExitCommand:
    pass
finally:
    print('finally will still run')

関連する質問:

18
Nagasaki45