Python의 스레드 내에서 호출 될 때 sys.exit ()가 종료되지 않는 이유는 무엇입니까?


98

이것은 어리석은 질문이 될 수 있지만 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 ()에 대한 호출이 해당 개별 인스턴스를 종료합니까? 그렇다면 스레딩 구현은 공유 리소스에 대한 액세스를 어떻게 관리합니까? 스레드에서 프로그램을 종료하려면 어떻게해야합니까 (실제로 원하는 것이 아니라 이해하도록하겠습니다)?

답변:


71

sys.exit()마찬가지로 SystemExit예외를 발생 thread.exit()시킵니다. 따라서 sys.exit()해당 스레드 내에서 해당 예외가 발생하면를 호출하는 것과 동일한 효과 thread.exit()가 있으므로 스레드 만 종료됩니다.


23

스레드에서 프로그램을 종료하려면 어떻게해야합니까?

Deestan이 설명한 메서드 외에는 호출 할 수 있습니다 os._exit(밑줄에주의). 그것을 사용하기 전에 (전화 또는 이와 유사한) 정리 가 없다는 것을 이해했는지 확인하십시오 __del__.


2
I / O를 플러시합니까?
Lorenzo Belli

1
os._exit (n) : "정리 처리기를 호출하거나 stdio 버퍼를 비우지 않고 상태 n으로 프로세스를 종료합니다."
Tim Richardson

때 유의 os._exit커스 내에서 사용 된 본체와이 정상 상태로 리셋하지 않는다. reset이 문제를 해결하려면 Unix-shell에서 실행해야합니다 .
sjngm

22

스레드에서 프로그램을 종료하려면 어떻게해야합니까 (실제로 원하는 것이 아니라 이해하도록하겠습니다)?

적어도 Linux에서는 다음을 수행 할 수 있습니다.

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

이것은 a SIGINT를 발생시키는 메인 스레드에 a 를 보냅니다 KeyboardInterrupt. 그것으로 당신은 적절한 정리가 있습니다. 원하는 경우 신호를 처리 할 수도 있습니다.

BTW : Windows에서는 SIGTERM신호 만 보낼 수 있으며 Python에서는 잡을 수 없습니다. 이 경우 os._exit동일한 효과로 간단히 사용할 수 있습니다 .


1
또한 달리 저주와 함께 작동 os._exit
sjngm

12

"pre main exit, post thread exit"가 인쇄된다는 사실이 당신을 괴롭히는가?

sys.exit( System.exit자바의 경우) 아날로그로 인해 VM / 프로세스 / 인터프리터가 즉시 중지 되는 다른 언어 (예 : Java)와 달리 Python은 sys.exit예외 (특히 SystemExit 예외) 만 발생합니다.

여기에 대한 문서입니다 sys.exit(단지는 print sys.exit.__doc__)

SystemExit (status)를 올려 인터프리터를 종료합니다.
상태가 생략되거나 없음 인 경우 기본값은 0 (즉, 성공)입니다.
상태가 숫자이면 시스템 종료 상태로 사용됩니다.
다른 종류의 개체 인 경우 인쇄되고 시스템
종료 상태는 하나 (즉, 실패)가됩니다.

다음과 같은 몇 가지 결과가 있습니다.

  • 스레드에서 전체 프로세스가 아닌 현재 스레드를 종료합니다 (스택의 맨 위에 있다고 가정합니다 ...).
  • 객체 소멸자 ( __del__)는 해당 객체를 참조하는 스택 프레임이 풀릴 때 잠재적으로 호출됩니다.
  • 스택이 풀릴 때 마지막으로 블록이 실행됩니다.
  • SystemExit예외를 잡을 수 있습니다

마지막은 아마도 가장 놀랍고, except파이썬 코드에 정규화되지 않은 문 이 거의 없어야하는 또 다른 이유 입니다.


11

스레드에서 프로그램을 종료하려면 어떻게해야합니까 (실제로 원하는 것이 아니라 이해하도록하겠습니다)?

내가 선호하는 방법은 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

3
Queue여기는 필요하지 않습니다 . 간단한 것만으로 bool도 괜찮습니다. 이 변수의 is_active기본 이름은 이고 초기 기본값은 True입니다.
Acumenus 2013

3
그래 정확 해. effbot.org/zone/thread-synchronization.htm 에 따르면 bool(또는 다른 원자 연산)을 수정하면 이 특정 문제에 완벽하게 적용됩니다. 내가 갈 이유 Queue들 나사 에이전트와 작업 할 때 나는 여러 가지 신호를 필요로 끝날하는 경향이있다 ( flush, reconnect, exit, 등 ...) 거의 즉시.
Deestan 2013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.