Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

스레드에서 발생한 파이썬 예외를 처리하는 방법

파이썬에서 멀티스레딩을 사용할 때 주의해야 할 중요한 점이 있습니다. 바로 스레드 내부에서 발생한 예외는 자동으로 메인 스레드로 전달되지 않는다는 것입니다. 따라서 예외를 적절히 처리하려면 별도의 메커니즘이 필요합니다.

Queue를 활용한 예외 전달 방법

가장 일반적인 해결 방법은 Queue 객체를 사용하는 것입니다. 각 스레드는 자신의 실행 결과와 함께 예외 정보를 큐에 담아두고, 메인 스레드가 이를 꺼내 확인하는 구조입니다. 아래 코드는 이러한 방식으로 예외를 처리하도록 작성된 예제입니다.

import sys
import threading
import time
import Queue

def thread(args1, stop_event, queue_obj):
    print "start thread"
    stop_event.wait(12)
    if not stop_event.is_set():
        try:
            raise Exception("boom!")
        except Exception:
            queue_obj.put(sys.exc_info())
            pass

try:
    queue_obj = Queue.Queue()
    t_stop = threading.Event()
    t = threading.Thread(target=thread, args=(1, t_stop, queue_obj))
    t.start()
    time.sleep(15)
    print "stop thread!"
    t_stop.set()

    try:
        exc = queue_obj.get(block=False)
    except Queue.Empty:
        pass
    else:
        exc_type, exc_obj, exc_trace = exc
        print exc_obj
except Exception as e:
    print "It took too long"

실행 결과

C:/Users/TutorialsPoint1/~.py
start thread
stop thread!
boom!

코드 동작 원리

이 코드의 핵심 흐름은 다음과 같습니다.

1. 예외 캡처: 스레드 함수 thread() 내부에서 의도적으로 Exception("boom!")을 발생시키고, try-except 블록으로 이를 잡습니다. 그런 다음 sys.exc_info()를 사용하여 현재 처리 중인 예외에 대한 정보(예외 타입, 예외 객체, 트레이스백)를 튜플 형태로 얻어 queue_obj에 저장합니다.

2. 이벤트 기반 종료 제어: threading.Event 객체(t_stop)를 통해 메인 스레드가 워커 스레드의 종료 시점을 제어합니다. stop_event.wait(12)는 최대 12초까지 대기하며, 그 안에 이벤트가 설정되지 않으면 스레드 내부 코드가 계속 실행됩니다.

3. 메인 스레드에서의 확인: 메인 스레드는 15초간 대기한 후 t_stop.set()으로 종료 신호를 보내고, 큐에서 예외 정보를 가져옵니다. queue_obj.get(block=False)는 비차단 방식으로 호출되므로, 큐가 비어 있으면 Queue.Empty 예외가 발생하며 이 경우 아무 작업도 수행하지 않습니다.

4. 예외 출력: 큐에서 예외 정보를 성공적으로 가져오면, 튜플을 언패킹하여 exc_type(예외 타입), exc_obj(예외 객체), exc_trace(트레이스백)로 분리한 뒤 예외 객체를 출력합니다. 실행 결과에서 볼 수 있듯이 boom!이라는 예외 메시지가 정상적으로 출력됩니다.

참고 사항

위 예제는 파이썬 2 스타일(print 문, Queue 모듈)로 작성되었습니다. 파이썬 3 환경에서는 print를 함수 형태로 사용하고, 모듈 이름을 queue로 변경해야 합니다. 또한 파이썬 3.8 이상에서는 threading.excepthook을 사용하거나, concurrent.futures.ThreadPoolExecutor를 활용하면 스레드의 예외를 더욱 간편하게 관리할 수 있습니다.

요약하면, 스레드에서 발생한 예외는 메인 스레드로 자동 전파되지 않으므로, 큐나 이벤트 같은 공유 자원을 통해 예외 정보를 명시적으로 전달하고 메인 스레드에서 이를 확인·처리하는 패턴을 사용하는 것이 안전하고 확실한 방법입니다.