Почему sys.exit () не завершается при вызове внутри потока в Python? - PullRequest
74 голосов
/ 25 мая 2009

Это может быть глупым вопросом, но я проверяю некоторые из моих предположений о Python, и меня смущает вопрос, почему следующий фрагмент кода не будет выходить при вызове в потоке, а завершится при вызове основная нить.

import sys, time
from threading import Thread

def testexit():
    time.sleep(5)
    sys.exit()
    print "post thread exit"

t = Thread(target = testexit)
t.start()
t.join()
print "pre main exit, post thread exit"
sys.exit()
print "post main exit"

Документы для sys.exit () утверждают, что вызов должен выйти из Python. Я могу видеть из результатов этой программы, что «выход из пост-потока» никогда не печатается, но основной поток просто продолжает работать даже после того, как поток вызывает выход.

Создается ли отдельный экземпляр интерпретатора для каждого потока, и вызов exit () просто выходит из этого отдельного экземпляра? Если да, то как реализация многопоточности управляет доступом к общим ресурсам? Что, если я захочу выйти из программы (не то, что я на самом деле хочу, а просто так понимаю)?

Ответы [ 5 ]

55 голосов
/ 25 мая 2009

sys.exit () вызывает исключение SystemExit, как и thread.exit (). Таким образом, когда sys.exit () вызывает это исключение внутри этого потока, оно имеет тот же эффект, что и вызов thread.exit (), поэтому выходит только поток.

17 голосов
/ 25 февраля 2011

Что если я захочу выйти из программы из потока?

Помимо описанного Дестаном метода, вы можете вызвать os._exit (обратите внимание на подчеркивание). Перед использованием убедитесь, что вы понимаете, что он не очищает (например, вызывает __del__ или подобное).

13 голосов
/ 18 августа 2011

Что делать, если я хочу выйти из программы (не то чтобы я на самом деле хочу, но только так я понимаю)?

По крайней мере, в Linux вы могли бы сделать что-то вроде:

os.kill(os.getpid(), signal.SIGINT)

Это отправляет SIGINT в основной поток, где он может быть обработан как KeyboardInterrupt.

Кстати: в Windows вы можете отправлять только сигнал SIGTERM, который не может быть перехвачен из Python. (там я бы предпочел позвонить os._exit, как предложено Хельмутом)

11 голосов
/ 25 мая 2009

Что если я захочу выйти из программы из потока (не то, что я на самом деле хочу, но только так я понимаю)?

Мой предпочтительный метод - передача сообщений Erlang-ish. Немного упрощенно, я делаю это так:

import sys, time
import threading
import Queue # thread-safe

class CleanExit:
  pass

ipq = Queue.Queue()

def testexit(ipq):
  time.sleep(5)
  ipq.put(CleanExit)
  return

threading.Thread(target=testexit, args=(ipq,)).start()
while True:
  print "Working..."
  time.sleep(1)
  try:
    if ipq.get_nowait() == CleanExit:
      sys.exit()
  except Queue.Empty:
    pass
11 голосов
/ 25 мая 2009

Напечатан ли факт, что вас беспокоит «до главного выхода, выхода из пост-нити»?

В отличие от некоторых других языков (например, Java), где аналог sys.exit (* в случае Java System.exit) приводит к немедленной остановке VM / процесса / интерпретатора, Python sys.exit просто вызывает исключение: исключение SystemExit в частности.

Вот документы для sys.exit (просто print sys.exit.__doc__):

Выйдите из интерпретатора, подняв SystemExit (status).
Если статус опущен или отсутствует, по умолчанию используется ноль (т. Е. Успех).
Если статус числовой, он будет использоваться в качестве статуса выхода из системы.
Если это объект другого типа, он будет напечатан и система
статус выхода будет один (т. е. ошибка).

Это имеет несколько последствий:

  • в потоке он просто убивает текущий поток, а не весь процесс (при условии, что он проходит до самого верха стека ...)
  • объектные деструкторы (__del__) потенциально вызываются как стековые фреймы, которые ссылаются на эти объекты, разматываются
  • наконец, блоки выполняются при разматывании стека
  • вы можете поймать SystemExit исключение

Последнее, пожалуй, самое удивительное и является еще одной причиной, по которой у вас почти никогда не должно быть неквалифицированного оператора except в вашем коде Python.

...