Jak zakończyć wątek po zakończeniu programu głównego?

85

Jeśli mam wątek w nieskończonej pętli, czy istnieje sposób na zakończenie go po zakończeniu głównego programu (na przykład po naciśnięciu Ctrl+ C)?

facha
źródło

Odpowiedzi:

46

Sprawdź to pytanie. Prawidłowa odpowiedź ma świetne wyjaśnienie, jak zakończyć wątki we właściwy sposób: czy istnieje sposób na zabicie wątku w Pythonie?

Aby zatrzymać wątek po sygnale przerwania klawiatury (ctrl + c), możesz przechwycić wyjątek „Przerwanie klawiatury” i wyczyścić przed zakończeniem. Lubię to:

try:
    start_thread()  
except (KeyboardInterrupt, SystemExit):
    cleanup_stop_thread()
    sys.exit()

W ten sposób możesz kontrolować, co robić, gdy program zostanie nagle przerwany.

Możesz także użyć wbudowanego modułu sygnałowego, który pozwala ustawić programy obsługi sygnału (w Twoim przypadku sygnał SIGINT): http://docs.python.org/library/signal.html

rogeriopvl
źródło
Bardzo dziękuję za twoją odpowiedź. Być może nie ułożyłem poprawnie tego pytania. W przykładzie podanym w tym pytaniu nadal konieczne było wykonanie funkcji stop () wątku. Kiedy kończę program nieprawidłowo przez ctrl + C, to nie może się zdarzyć. Więc moje pytanie brzmi trochę jak „jak wywołać funkcję mythread.stop (), jeśli przepływ głównego wątku zostanie przerwany”
facha
1
Czy jest cleanup_stop_thread()to funkcja globalna, której mogę używać? czy powinienem to zaimplementować?
Alper
@alper, myślę, że to był tylko przykład, że można coś zaimplementować. Powinieneś to wdrożyć
Leonardo Rick
98

Jeśli utworzysz wątki robocze wątków demonów, zginą one, gdy wszystkie wątki inne niż demonowe (np. Wątek główny) zostaną zamknięte.

http://docs.python.org/library/threading.html#threading.Thread.daemon

ʇsәɹoɈ
źródło
4
Dzięki za prostą i precyzyjną odpowiedź, domyślny wątek.Stan demona wątku isDaemon()to False, ustaw go jako True przez setDaemon(True).
Tong
3
To odpowiada na pytanie i po prostu działa. Generalnie operacja nie pytała, jak porządnie wyjść z wątków.
Johannes Overmann
1
isDaemon()i setDaemon()są starymi daemon=Truethreading.Thread()
programami pobierającymi
1
Zauważ, że używanie wątków demonów może powodować inne problemy i prawdopodobnie nie jest tym, czego chcesz tutaj: stackoverflow.com/questions/20596918/ ...
Doopy
Aby uniknąć używania wątków demonów i czysto zabijaj wątki, zobacz stackoverflow.com/questions/58910372/ ...
Pat-Laugh
15

Spróbuj włączyć pod-wątek jako demon-wątek.

Na przykład:

Zalecana:

from threading import Thread

t = Thread(target=<your-method>)
t.daemon = True  # This thread dies when main thread (only non-daemon thread) exits.
t.start()

W tekście:

t = Thread(target=<your-method>, daemon=True).start()

Stary interfejs API:

t.setDaemon(True)
t.start()

Kiedy twój główny wątek się kończy ("tj. Kiedy naciskam Ctrl+ C"), inne wątki również zostaną zabite przez powyższe instrukcje.

Benyamin Jafari
źródło
1
Zauważ, że korzystanie z wątków demonów może powodować inne problemy i prawdopodobnie nie są tym, czego chcesz tutaj: stackoverflow.com/questions/20596918/ ...
Doopy
12

Użyj modułu atexit standardowej biblioteki Pythona, aby zarejestrować funkcje "kończące", które są wywoływane (w głównym wątku) przy każdym rozsądnie "czystym" zakończeniu głównego wątku, w tym nieprzechwyconych wyjątkach, takich jak KeyboardInterrupt. Takie funkcje kończące mogą (choć nieuchronnie w głównym wątku!) Wywołać dowolną stopfunkcję, której potrzebujesz; wraz z możliwością ustawienia wątku jako daemon, daje to narzędzia do prawidłowego zaprojektowania potrzebnej funkcjonalności systemu.

Alex Martelli
źródło
Zauważ, że to podejście działało bez wymagania demonizowanych wątków w wersjach Pythona wcześniejszych niż 2.6.5, zobacz odpowiedź na stackoverflow.com/questions/3713360/… . To niefortunne IMHO, ponieważ wątki demonów podczas zamykania systemu są trochę bałaganem przed pythonem 3.4 ( bugs.python.org/issue19466 ). Jeśli zatrzymasz się i dołączysz do wątków demona w programach obsługi atexit, wszystko powinno być w porządku, przy (prawdopodobnie nieznacznym) koszcie serializacji porzucenia wątku.
NeilenMarais
Pamiętaj, że dziwne rzeczy mogą się zdarzyć z powodu opóźnionych atexit.register()wywołań w modułach Pythona, powodując, że twoja procedura kończenia zostanie wykonana po tej multiprocessing. Uruchamiam w tym problemie zajmując się wątkami Queuei daemon: „Błąd EOF” przy wyjściu programu przy użyciu kolejki wieloprocesowej i wątku .
Delgan
Najwyraźniej w nowoczesnych wersjach Pythona, takich jak 3.7.4+, programy atexitobsługi nie są wywoływane, gdy wątki inne niż demonowe są aktywne i główny wątek zostaje zamknięty. Zobacz Skrypt utknął podczas zamykania wątków przy użyciu atexit .
martineau
9

Jeśli stworzysz taki wątek - myThread = Thread(target = function)- a potem zrób myThread.start(); myThread.join(). Po zainicjowaniu CTRL-C wątek główny nie kończy pracy, ponieważ oczekuje na to myThread.join()wywołanie blokujące . Aby to naprawić, po prostu ustaw limit czasu na wywołanie .join (). Limit czasu może być tak długi, jak chcesz. Jeśli chcesz, aby czekał w nieskończoność, po prostu ustaw naprawdę długi limit czasu, na przykład 99999. Dobrą praktyką jest również zrobienie tego, myThread.daemon = Trueaby wszystkie wątki zostały zakończone po zakończeniu głównego wątku (nie będącego demonem).

Milean
źródło
myThread.daemon = Trueto wspaniałe rozwiązanie tego problemu.
Brannon
5
@Brannon .daemon=Truenie jest solidnym rozwiązaniem. Sprawdź ten wątek, aby uzyskać wyjaśnienie: stackoverflow.com/a/20598791/5562492
Odyssee
2

Wątki demona są zabijane niezręcznie, więc żadne instrukcje finalizatora nie są wykonywane. Możliwym rozwiązaniem jest sprawdzenie, czy główny wątek żyje, a nie nieskończona pętla.

Np. Dla Pythona 3:

while threading.main_thread().isAlive():
    do.you.subthread.thing()
gracefully.close.the.thread()

Zobacz Sprawdź, czy wątek główny nadal żyje z innego wątku .

umi
źródło