Подтвердить что ты не робот

Как выйти из всего приложения из потока Python?

Как я могу выйти из всего приложения Python из одного из его потоков? sys.exit() только завершает поток, в котором он вызывается, поэтому это не помогает.

Я не хотел бы использовать решение os.kill(), так как это не очень чисто.

4b9b3361

Ответ 1

Если все ваши потоки, кроме основных, являются демонами, лучший подход обычно thread.interrupt_main() - любой поток может использовать его чтобы поднять KeyboardInterrupt в основной поток, что обычно может привести к разумному очистке выхода из основного потока (включая финализаторы в вызываемом основном потоке и т.д.).

Конечно, если это приводит к тому, что какой-то поток не-демона поддерживает весь процесс, вам нужно следить за ним с помощью os._exit, как рекомендует Mark, но я видел бы это как последнее средство (вроде как kill -9;-), потому что он прекращает работу довольно грубо (финализаторы не запускаются, включая try/finally блоки, with блоки, atexit функции и т.д.).

Ответ 2

Короткий ответ: используйте 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 вместо простых чисел, как я использовал в приведенном выше примере.

Ответ 3

Использование 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')

Похожие вопросы: