Как завершить поток при завершении основной программы?

86

Если у меня есть поток в бесконечном цикле, есть ли способ завершить его, когда основная программа завершится (например, когда я нажму Ctrl+ C)?

фаха
источник

Ответы:

46

Отметьте этот вопрос. Правильный ответ содержит отличное объяснение того, как правильно завершить потоки: есть ли способ убить поток в Python?

Чтобы остановить поток по сигналу прерывания клавиатуры (ctrl + c), вы можете перехватить исключение «KeyboardInterrupt» и выполнить очистку перед выходом. Как это:

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

Таким образом, вы можете контролировать, что делать, когда программа внезапно завершается.

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

Rogeriopvl
источник
Большое спасибо за ваш ответ. Возможно, я неправильно сформулировал вопрос. В примере, приведенном в этом вопросе, по-прежнему необходимо было выполнить функцию stop () потока. Когда я аварийно завершаю программу нажатием ctrl + C, этого не может быть. Итак, мой вопрос немного похож на «как мне вызвать функцию Myhread.stop (), если поток основного потока прерван»
facha 01
1
Является ли cleanup_stop_thread()глобальная функция , которую я могу использовать? или мне нужно это реализовать?
alper
@alper, я думаю, может быть, это был просто пример, что можно что-то реализовать. Вы должны реализовать это
Леонардо Рик
100

Если вы сделаете свои рабочие потоки демоническими потоками, они умрут, когда все ваши недемонические потоки (например, основной поток) завершатся.

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

ʇsәɹoɈ
источник
4
Спасибо за простой и точный ответ, по умолчанию threading.Thread daemon status isDaemon()имеет статус False, установите True с помощью setDaemon(True).
Тонг
3
Это отвечает на вопрос и просто работает. Оп не спрашивал как вообще чисто выйти из потоков.
Johannes Overmann
1
isDaemon()и setDaemon()являются старыми геттерами / сеттерами (согласно приведенному выше документу), просто используйте daemon=Trueinthreading.Thread()
fabio.sang
1
Обратите внимание, что использование потоков демонов может вызвать другие проблемы и, вероятно, не то, что вам нужно здесь: stackoverflow.com/questions/20596918/…
Doopy
Чтобы избежать использования потоков демона и полностью уничтожить потоки, см. Stackoverflow.com/questions/58910372/…
пользователь
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функцию, которая вам нужна; вместе с возможностью настройки потока as daemon, это дает вам инструменты для правильного проектирования необходимых вам системных функций.

Алекс Мартелли
источник
Обратите внимание, что этот подход работал без необходимости демонизировать потоки в версиях Python до 2.6.5, см. Ответ на stackoverflow.com/questions/3713360/… . Это прискорбно, ИМХО, поскольку потоки демонов во время выключения выглядят немного беспорядочно до python 3.4 ( bugs.python.org/issue19466 ). Если вы остановитесь и присоединитесь к потокам демона в обработчиках atexit, все должно быть в порядке, при (возможно, незначительной) стоимости сериализации разрыва потока.
NeilenMarais
Имейте в виду, что из-за постпонированных atexit.register()вызовов в модулях Python могут происходить странные вещи , в результате чего ваша процедура завершения будет выполняться после процедуры завершения multiprocessing. Я бег в этой проблеме , ЗАНИМАЮЩИЙСЯ Queueи daemonнитях: «ошибка EOF» при выходе из программы с использованием многопроцессорной обработки очереди и темы .
Delgan
Очевидно, что в современных версиях Python, таких как 3.7.4+, atexitобработчики не вызываются, когда не- демонические потоки активны и основной поток завершается. См. « Сценарий зависает при выходе» при использовании atexit для завершения потоков .
martineau
9

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

Milean
источник
myThread.daemon = Trueпрекрасное решение этой проблемы.
Brannon
5
@Brannon .daemon=Trueне является твердым решением. Посмотрите эту
ветку
2

Потоки демона уничтожаются без должного внимания, поэтому никакие инструкции финализатора не выполняются. Возможное решение - проверить, жив ли основной поток, а не бесконечный цикл.

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

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

См. Проверка, активен ли основной поток из другого потока .

umi
источник