Почему sys.exit() не выход при вызове внутри потока в Python?
это может быть глупый вопрос, но я тестирую некоторые из моих предположений о 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. Я вижу из вывода этой программы, что" post thread exit " никогда не печатается, но основной поток просто продолжает идти даже после того, как поток вызывает exit.
является ли отдельный экземпляр интерпретатора создается для каждого потока, и вызов exit() просто выходит из этого отдельного экземпляра? Если да, то как потоковая реализация управляет доступом к общим ресурсам? Что делать, если я действительно хочу выйти из программы из потока (не то, что я действительно хочу, но просто так понимаю)?
5 ответов:
sys.exit () вызывает исключение SystemExit, как и thread.выход.)( Так, когда сис.exit () вызывает это исключение внутри этого потока, оно имеет тот же эффект, что и вызов потока.exit (), поэтому выходит только поток.
Что делать, если я хочу выйти из программы из потока (не то что я на самом деле хочу, но только так я понимаю)?
по крайней мере на Linux, вы могли бы сделать что-то вроде:
os.kill(os.getpid(), signal.SIGINT)
это отправить SIGINT в основной поток, где он может быть обработан как KeyboardInterrupt.
BTW: в Windows вы можете отправлять только сигнал SIGTERM, который не может быть пойман с Python. (там я бы предпочел называть ОС._exit как предложил Хельмут)
Что делать, если я действительно хочу выйти из программы из потока (не то, что я на самом деле хотите, но только так я понимаю)?
мой предпочтительный метод-передача сообщений Erlang-ish. Немного simlified, я делаю это так:
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
Что делать, если я действительно хочу выйти из программы из потока?
помимо описанного метода Deestan вы можете вызвать
os._exit
(обратите внимание на подчеркивание). Перед его использованием убедитесь, что вы понимаете, что он делает нет очистка (например, вызов__del__
или подобные).
является ли тот факт, что "pre main exit, post thread exit" печатается, что вас беспокоит?
в отличие от некоторых других языков (например, Java), где аналог
sys.exit
(System.exit
, в случае Java) заставляет VM / process / interpreter немедленно останавливаться, Pythonsys.exit
просто выдает исключение: исключение SystemExit в частности.вот документы для
sys.exit
(всегоprint sys.exit.__doc__
):выйти из интерпретатора путем повышения SystemExit(статус).
Если статус опущен или отсутствует, он по умолчанию равен нулю (т. е. успех).
Если состояние числовое, оно будет использоваться в качестве состояния выхода из системы.
Если это другой вид объекта, он будет напечатан и система
статус выхода будет один (т. е. сбой).это имеет несколько последствий:
- в потоке он просто убивает текущий поток, а не весь процесс (предполагая, что он получает все путь к вершине стека...)
- деструктор объекта (
__del__
) потенциально вызываются как кадры стека, которые ссылаются на эти объекты разматываются- наконец блоки выполняются по мере разматывания стека
- вы можете поймать
SystemExit
исключениепоследнее, возможно, самое удивительное, и это еще одна причина, почему вы должны почти никогда не имеют безусловного
except
оператор в вашем коде Python.