2009-05-25 5 views
59

이것은 바보 같은 질문 일 수 있지만 파이썬에 대한 내 가정을 테스트하고 있는데 다음 코드 스 니펫이 스레드에서 호출 될 때 종료되지 않는 이유에 대해 혼란 스럽지만 주 스레드에서 호출 될 때 종료됩니다 실.파이썬에서 스레드 내에서 호출 될 때 sys.exit()가 종료되지 않는 이유는 무엇입니까?

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()에 대한 문서에서 파이썬을 종료해야한다고 나와 있습니다. 나는이 프로그램의 결과에서 "post thread exit"가 결코 출력되지 않는다는 것을 알 수있다. 그러나 메인 쓰레드는 thread가 exit를 호출 한 후에도 계속 진행한다.

인터프리터의 별도 인스턴스가 각 스레드에 대해 만들어지고 exit()를 호출하면 해당 인스턴스가 종료됩니까? 그렇다면 스레딩 구현이 공유 리소스에 대한 액세스를 어떻게 관리합니까? 스레드에서 프로그램을 종료하고 싶다면 (실제로 원하는 것은 아니지만 단지 이해할 수 있습니다)?

답변

47

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

8

"pre main exit, post thread exit"가 인쇄된다는 사실이 당신을 괴롭 히고 있습니까? (자바의 경우 System.exit) sys.exit 아날로그 즉시 중지 VM/프로세스/통역이 발생

다른 언어와는 달리 (자바 등), 파이썬의 sys.exit는 예외가 발생합니다 : 특히 SystemExit없이 예외를. SystemExit없이 (상태)를 제기하여

종료 인터프리터 : 여기

sys.exit에 대한 문서 (단지 print sys.exit.__doc__)입니다.
상태가 생략되거나 없음 인 경우 기본값은 0 (즉, 성공)입니다.
상태가 숫자 인 경우 시스템 종료 상태로 사용됩니다.
다른 종류의 객체 인 경우 인쇄되고 시스템
종료 상태가 하나 (즉, 실패)가됩니다.

이 몇 가지 결과가 있습니다 스레드에서

  • 그냥 현재의 thread가 아닌 전체 프로세스 명을 (... 그것은 모든 방법 스택의 상단에 도달 가정)
  • 객체 소멸자 (__del__)이 잠재적으로 그 개체
  • 마지막 블록이 스택으로 실행 풀려있는 참조 스택 프레임으로서 호출
  • 할 수 풀릴 마지막은 아마도 가장 놀라운이며, 당신이 당신의 파이썬 코드에 규정 화되지 않은 except 문이 거의 절대해야하는 이유 또 다른 이유입니다 SystemExit 예외

을 잡을 수있어.

12

내가 (내가 실제로 가 원하지만 너무 이해하지 않는 것이) 스레드에서 프로그램 을 종료 할 않은 경우?

내가 선호하는 방법은 얼랭이즘 메시지 전달 방법입니다. 약간 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 
+2

여기에 '대기열'이 필요 없습니다. 단순한'bool' 만 잘 할 것입니다. 이 변수의 전형적인 이름은'is_active'이고 초기 기본값은'True'입니다. –

+3

네, 맞습니다. http://effbot.org/zone/thread-synchronization.htm에 따르면 'bool'(또는 다른 원자 연산)을 수정하면이 특정 문제를 완벽하게 수행 할 수 있습니다. 내가'Queue'를 사용하는 이유는 스레드 된 에이전트로 작업 할 때 거의 즉시 여러 가지 다른 신호 ('flush','reconnect','exit' 등)를 필요로한다는 것입니다. – Deestan

9

내가 프로그램 스레드에서 를 종료 할 않은 경우?

Deestan에서 설명한 방법 외에도 os._exit (밑줄에 유의하십시오)이라고 부를 수 있습니다. 사용하기 전에 청소 (예 : __del__ 또는 그 유사)를 수행한다는 것을 이해했는지 확인하십시오.

+0

I/O를 비 웁니 까? –

11

스레드에서 프로그램을 종료하고 싶다면 (실제로는 이 아니라 실제로 이해함)? 그것이 KeyboardInterrupt으로 처리 할 수있는 메인 스레드에 SIGINT를 보내

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

이 :

은 적어도 리눅스에 당신이 뭔가를 할 수 있습니다.

BTW : Windows에서는 SIGTERM 신호 만 보낼 수 있습니다.이 신호는 파이썬에서 포착 할 수 없습니다. (Helmut에서 제안한대로 os._exit을 호출하는 것이 더 좋을 것입니다.)