Może to być głupie pytanie, ale testuję niektóre z moich założeń dotyczących Pythona i nie wiem, dlaczego następujący fragment kodu nie kończy się po wywołaniu w wątku, ale kończy się po wywołaniu w wątku głównym.
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"
Dokumentacja sys.exit () stwierdza, że wywołanie powinno zakończyć się z Pythona. Widzę na wyjściu tego programu, że „post wątek wyjścia” nigdy nie jest drukowany, ale główny wątek po prostu działa nawet po wywołaniu wątku wyjścia.
Czy dla każdego wątku tworzona jest osobna instancja interpretera, a wywołanie exit () właśnie kończy pracę z tej oddzielnej instancji? Jeśli tak, w jaki sposób implementacja obsługi wątków zarządza dostępem do współdzielonych zasobów? A co jeśli chciałbym wyjść z programu z wątku (nie to, że tak naprawdę chcę, ale tylko po to, żeby zrozumieć)?
źródło
os._exit
jest używany w curses, konsola nie jest resetowana do normalnego stanu z tym.reset
Aby to naprawić, musisz wykonać w powłoce Uniksa.W systemie Linux:
To wysyła
SIGINT
do głównego wątku, który podnosiKeyboardInterrupt
. Dzięki temu masz porządne porządki. Możesz także zarejestrować handlera, jeśli chcesz inaczej zareagować.Powyższe nie działa w systemie Windows, ponieważ można wysłać tylko
SIGTERM
sygnał, który nie jest obsługiwany przez Pythona i ma taki sam efekt jaksys._exit()
.Dla Windowsa:
Po prostu użyj:
Spowoduje to zamknięcie całego procesu. Jednak bez czyszczenia. Jeśli tego potrzebujesz, musisz komunikować się z głównym wątkiem w inny sposób.
źródło
Czy to, że jest drukowane „przed wyjściem głównym, wyjście z wątku po”, cię niepokoi?
W przeciwieństwie do niektórych innych języków (takich jak Java), w których odpowiednik
sys.exit
(System.exit
w przypadku Javy) powoduje natychmiastowe zatrzymanie maszyny wirtualnej / procesu / interpretera, język Python posys.exit
prostu zgłasza wyjątek: w szczególności wyjątek SystemExit.Oto dokumenty dla
sys.exit
(tylkoprint sys.exit.__doc__
):Ma to kilka konsekwencji:
__del__
) są potencjalnie wywoływane, gdy ramki stosu odwołujące się do tych obiektów są rozwijaneSystemExit
wyjątekTo ostatnie jest prawdopodobnie najbardziej zaskakujące i jest kolejnym powodem, dla którego prawie nigdy nie powinieneś mieć niekwalifikowanej
except
instrukcji w kodzie Pythona.źródło
Moją preferowaną metodą jest przekazywanie wiadomości Erlang-ish. Nieco uproszczone, robię to tak:
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
źródło
Queue
tutaj. Wystarczy prostybool
zabieg. Klasyczna nazwa tej zmiennej to,is_active
a jej początkowa wartość domyślna toTrue
.bool
(lub jakiejkolwiek innej operacji atomowej) będzie idealnie pasować do tego konkretnego problemu. Powodem idę zQueue
s jest to, że podczas pracy z czynnikami gwintowanych staram się skończyć potrzebuje kilku różnych sygnałów (flush
,reconnect
,exit
, etc ...) niemal natychmiast.bool
działałoby, jak zauważył @Acumenus, to podobnieint
wydaje się, że proste byłoby wszystko, co jest potrzebne do obsługi kilku różnych sygnałów -bool
wint
końcu jest tylko podklasą .