Як завершити потік, коли закінчується основна програма?


85

Якщо у мене є потік у нескінченному циклі, чи є спосіб його завершити, коли закінчується основна програма (наприклад, коли я натискаю Ctrl+ C)?

Відповіді:


46

Перевірте це питання. Правильна відповідь має чудове пояснення того, як правильно завершити потоки: чи є спосіб вбити Thread у Python?

Щоб потік зупинився на сигналі переривання клавіатури (ctrl + c), ви можете зафіксувати виняток "KeyboardInterrupt" і очищення перед виходом. Подобається це:

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

Таким чином ви можете контролювати, що робити, коли програма різко припиняється.

Ви також можете використовувати вбудований модуль сигналу, який дозволяє вам налаштувати обробники сигналів (у вашому випадку сигнал SIGINT): http://docs.python.org/library/signal.html


Велике спасибі за вашу відповідь. Можливо, я не правильно поставив питання. У прикладі, наведеному в цьому питанні, все одно потрібно було виконати функцію stop () потоку. Коли я аномально припиняю програму за допомогою ctrl + C, цього не може статися. Отже, моє запитання трохи нагадує: "як мені викликати функцію mythread.stop (), якщо основний потік потоку перерваний"
facha

1
Чи cleanup_stop_thread()можу я використовувати глобальну функцію? або мені потрібно це реалізувати?
alper

@alper, я думаю, можливо, це був лише приклад, де можна щось реалізувати. Ви повинні це здійснити
Леонардо Рік,

98

Якщо ви зробите свої робочі потоки демоновими потоками, вони загинуть, коли всі ваші недемонові потоки (наприклад, основний потік) вийдуть.

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


4
Дякуємо за просту і точну відповідь, за промовчанням вирізання потоків. Статус потоку потоку isDaemon()- False, встановіть його True by setDaemon(True).
Тонг,

3
Це відповідає на питання і просто працює. Оператор не запитував, як взагалі чисто вийти з потоків.
Йоханнес Оверманн

1
isDaemon()і setDaemon()старі геттери / сеттери (згідно пов'язаного з документом вище), просто використовуйте daemon=Trueвthreading.Thread()
fabio.sang

1
Зверніть увагу , що з допомогою демона теми може викликати інші проблеми , і, ймовірно , не те , що ви хочете тут: stackoverflow.com/questions/20596918 / ...
Doopy

Щоб уникнути використання демонових потоків та чистого вбивання потоків, див. Stackoverflow.com/questions/58910372/…
Pat-Laugh

15

Спробуйте увімкнути підпотік як потік демона.

Наприклад:

Рекомендовано:

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()

В лінію:

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

Старий API:

t.setDaemon(True)
t.start()

Коли ваш основний потік закінчується ("тобто, коли я натискаю Ctrl+ C"), інші потоки також будуть вбиті відповідно до інструкцій вище.


1
Зверніть увагу , що з допомогою демона теми може викликати інші проблеми , і, ймовірно , не те , що ви хочете тут: stackoverflow.com/questions/20596918 / ...
Doopy

12

Використовуйте модуль atexit стандартної бібліотеки Python для реєстрації функцій "завершення", які викликаються (в основному потоці) при будь-якому розумно "чистому" завершенні основного потоку, включаючи незахоплений виняток, такий як KeyboardInterrupt. Такі функції завершення можуть (хоч і неминуче в основному потоці!) Викликати будь-яку потрібну stopвам функцію; разом з можливістю встановити потік як daemon, що дає вам інструменти для правильного проектування необхідних функціональних можливостей системи.


Зверніть увагу, що цей підхід працював, не вимагаючи демонізованих потоків у версіях Python до 2.6.5, див. Відповідь на stackoverflow.com/questions/3713360/… . Це прикро IMHO, оскільки демонові потоки під час вимкнення трохи псують перед python 3.4 ( bugs.python.org/issue19466 ). Якщо ви зупинитеся і приєднаєте свої демонові потоки до своїх обробників atexit, все повинно бути добре, за (можливо, незначної) вартості серіалізації відключення вашого потоку.
NeilenMarais

Майте на увазі, що дивні речі можуть трапитися через відкладені atexit.register()виклики в модулях Python, в результаті чого ваша процедура завершення буде виконана після процедури multiprocessing. Я працюю з цією проблемою, що стосується Queueі daemonпотоків: "Помилка EOF" при виході з програми за допомогою багатопроцесорної черги та потоку .
Делган

Очевидно, що в сучасних версіях Python, таких як 3.7.4+, atexitобробники не викликаються, коли недемонові потоки живі і основний потік виходить. Див. Скрипт, застрягший на виході при використанні atexit для завершення потоків .
Мартіно

9

Якщо ви породжуєте нитку так myThread = Thread(target = function)- і тоді робіть myThread.start(); myThread.join(). Коли ініціюється CTRL-C, основний потік не виходить, оскільки він чекає на цей myThread.join()виклик блокування . Щоб це виправити, просто встановіть час очікування на дзвінок .join (). Час очікування може бути скільки завгодно. Якщо ви хочете, щоб це чекало нескінченно, просто вставте дуже великий час очікування, наприклад 99999. Це також хороша практика, щоб зробити myThread.daemon = Trueтак, щоб усі потоки виходили, коли основний потік (не демон) виходить.


myThread.daemon = Trueє чудовим рішенням цієї проблеми.
Бреннон,

5
@Brannon .daemon=Trueне в твердому розчині. Перевірте цю тему для пояснення: stackoverflow.com/a/20598791/5562492
Одіссея

2

Потоки демона вбиваються недобросовісно, ​​тому будь-які вказівки завершувача не виконуються. Можливим рішенням є перевірка, чи основний потік живий, а не нескінченний цикл.

Наприклад, для Python 3:

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

Див. Перевірте, чи основна нитка все ще жива з іншого потоку .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.