Как я могу выйти из всего приложения Python из одного из его потоков? sys.exit() только завершает поток, в котором он вызывается, поэтому это не помогает.
Я не хотел бы использовать решение os.kill(), так как это не очень чисто.
Как я могу выйти из всего приложения Python из одного из его потоков? sys.exit() только завершает поток, в котором он вызывается, поэтому это не помогает.
Я не хотел бы использовать решение os.kill(), так как это не очень чисто.
Если все ваши потоки, кроме основных, являются демонами, лучший подход обычно thread.interrupt_main() - любой поток может использовать его чтобы поднять KeyboardInterrupt
в основной поток, что обычно может привести к разумному очистке выхода из основного потока (включая финализаторы в вызываемом основном потоке и т.д.).
Конечно, если это приводит к тому, что какой-то поток не-демона поддерживает весь процесс, вам нужно следить за ним с помощью os._exit
, как рекомендует Mark, но я видел бы это как последнее средство (вроде как kill -9
;-), потому что он прекращает работу довольно грубо (финализаторы не запускаются, включая try/finally
блоки, with
блоки, atexit
функции и т.д.).
Короткий ответ: используйте os._exit
.
Длинный ответ с примером:
Я дернул и немного изменил простой пример нитки из учебник по DevShed:
import threading, sys, os
theVar = 1
class MyThread ( threading.Thread ):
def run ( self ):
global theVar
print 'This is thread ' + str ( theVar ) + ' speaking.'
print 'Hello and good bye.'
theVar = theVar + 1
if theVar == 4:
#sys.exit(1)
os._exit(1)
print '(done)'
for x in xrange ( 7 ):
MyThread().start()
Если вы оставите sys.exit(1)
закомментированным, script умрет после того, как выйдет третий поток. Если вы используете sys.exit(1)
и комментируете os._exit(1)
, третий поток не печатает (done)
, а программа проходит через все семь потоков.
os._exit
"обычно должен использоваться только в дочернем процессе после fork()", и отдельный поток достаточно близко к нему для вашей цели. Также обратите внимание, что на этой странице руководства есть несколько перечисленных значений сразу после os._exit
, и вы должны предпочесть их как аргументы os._exit
вместо простых чисел, как я использовал в приведенном выше примере.
Использование thread.interrupt_main()
может не помочь в некоторой ситуации. KeyboardInterrupt
часто используются в приложениях командной строки для выхода из текущей команды или для очистки строки ввода.
Кроме того, os._exit
немедленно уничтожит процесс, не запустив в вашем коде finally
, что может быть опасно (например, файлы и соединения не будут закрыты).
Решение, которое я нашел, это зарегистрировать обработчик сигнала в основном потоке, который вызывает настраиваемое исключение. Используйте фоновый поток, чтобы запустить сигнал.
import signal
import os
import threading
import time
class ExitCommand(Exception):
pass
def signal_handler(signal, frame):
raise ExitCommand()
def thread_job():
time.sleep(5)
os.kill(os.getpid(), signal.SIGUSR1)
signal.signal(signal.SIGUSR1, signal_handler)
threading.Thread(target=thread_job).start() # thread will fire in 5 seconds
try:
while True:
user_input = raw_input('Blocked by raw_input loop ')
# do something with 'user_input'
except ExitCommand:
pass
finally:
print('finally will still run')
Похожие вопросы: