これはばかげた質問かもしれませんが、Pythonについての私の仮定のいくつかをテストしており、スレッドで呼び出されたときに次のコードスニペットが終了しない理由について混乱していますが、メインスレッドで呼び出されると終了します。
import sys, time
from threading import Thread
def testexit():
time.sleep(5)
sys.exit()
print "post thread exit"
t = Thread(target = testexit)
t.start()
t.join()
print "pre main exit, post thread exit"
sys.exit()
print "post main exit"
Sys.exit()のドキュメントには、呼び出しはPythonから終了する必要があると記載されています。このプログラムの出力から、「スレッド終了後」は決して出力されないことがわかりますが、メインスレッドは、スレッドがexitを呼び出した後も継続します。
スレッドごとにインタープリターの個別のインスタンスが作成されており、exit()の呼び出しがその個別のインスタンスを終了しているだけですか?もしそうなら、スレッド実装は共有リソースへのアクセスをどのように管理しますか?スレッドからプログラムを終了したい場合はどうすればよいですか(実際にしたいのではなく、理解しただけです)。
sys.exit()は、thread.exit()と同様にSystemExit例外を発生させます。したがって、sys.exit()がそのスレッド内でその例外を発生させると、thread.exit()を呼び出すのと同じ効果があります。そのため、スレッドのみが終了します。
スレッドからプログラムを終了したい場合はどうなりますか?
説明したメソッドDeestanとは別に、os._exit
(アンダースコアに注意してください)。使用する前に、それがno cleanups(__del__
または類似)。
スレッドからプログラムを終了したい場合はどうすればよいですか(実際にしたいのではなく、理解しただけです)。
少なくともLinuxでは、次のようなことができます。
os.kill(os.getpid(), signal.SIGINT)
これにより、SIGINTがメインスレッドに送信され、KeyboardInterruptとして処理できます。
ところで:Windowsでは、SIGTERMシグナルのみを送信できますが、Pythonからはキャッチできません。 (私はHelmutが示唆するos._exitを呼び出すことを好むでしょう)
「メイン終了前、スレッド終了後」が表示されているという事実は、あなたを悩ますものですか?
sys.exit
(Javaの場合はSystem.exit
に類似)がVM /プロセス/インタープリターをすぐに停止させる他の言語(Javaなど)とは異なり、Pythonのsys.exit
は例外をスローします。特にSystemExit例外。
sys.exit
(ちょうどprint sys.exit.__doc__
)のドキュメントは次のとおりです。
SystemExit(status)を上げてインタープリターを終了します。
ステータスが省略された場合、またはなしの場合、デフォルトはゼロ(つまり成功)になります。
ステータスが数値の場合、システム終了ステータスとして使用されます。
別の種類のオブジェクトの場合、印刷され、システム
終了ステータスは1(つまり、失敗)になります。
これにはいくつかの結果があります。
__del__
)は、それらのオブジェクトを参照するスタックフレームが巻き戻されると潜在的に呼び出されますSystemExit
例外をキャッチできます最後はおそらく最も驚くべきことであり、あなたのPythonコードに未修飾のexcept
ステートメントがほとんど決してないはずであるもう一つの理由です。
スレッドからプログラムを終了したい場合はどうすればよいですか(実際にしたいのではなく、理解しただけです)。
私が好む方法は、アーランっぽいメッセージの受け渡しです。少し簡略化して、次のようにします。
import sys, time
import threading
import Queue # thread-safe
class CleanExit:
pass
ipq = Queue.Queue()
def testexit(ipq):
time.sleep(5)
ipq.put(CleanExit)
return
threading.Thread(target=testexit, args=(ipq,)).start()
while True:
print "Working..."
time.sleep(1)
try:
if ipq.get_nowait() == CleanExit:
sys.exit()
except Queue.Empty:
pass