>  기사  >  백엔드 개발  >  파이썬에서 스레드를 종료하는 방법

파이썬에서 스레드를 종료하는 방법

藏色散人
藏色散人원래의
2021-03-02 14:02:3460060검색

Python에서 스레드를 종료하는 방법: 1. stop 함수를 호출하고 Join 함수를 사용하여 스레드가 제대로 종료될 때까지 기다립니다. 2. Python 스레드에서 예외를 발생시킵니다. 3. "thread.join"을 사용하여 종료합니다. 스레드.

파이썬에서 스레드를 종료하는 방법

이 기사의 운영 환경: Windows 7 시스템, Python 버전 3.5, DELL G3 컴퓨터.

머리말 · Zero

파이썬에서 스레드를 종료하려면 일반적인 방법은 설정/확인 --->플래그 또는 잠금이라는 것을 알고 있습니다.

이 방법이 좋은가요?

좋으면 안 돼요! 모든 프로그래밍 언어에서 스레드를 갑자기 종료하는 것은 어쨌든 좋은 디자인 패턴이 아니기 때문입니다.

동시에

다음과 같은 경우에는 더욱 악화됩니다.

  • 읽기 및 쓰기 가능한 파일을 여는 등 스레드가 합리적으로 닫아야 하는 중요한 리소스를 열 때
  • 스레드; 여러 개의 다른 스레드를 생성한 경우 이러한 스레드도 닫아야 합니다(하위 스레드가 떠돌아다닐 위험이 있습니다!).

간단히 말하면, 공통 리소스를 공유하는 대규모 스레드 그룹이 있습니다. 스레드 중 하나가 리소스를 차지하게 되면 강제로 떠나게 되는 결과가 발생합니다. 리소스가 잠겨 있어 아무도 얻을 수 없습니다. 불멸자를 키우는 소설의 줄거리와 좀 비슷하지 않나요?

스레딩이 시작만 되고 끝이 없는 이유를 아시나요?

스레드는 일반적으로 네트워크 연결, 시스템 리소스 해제, 스트리밍 파일 덤프에 사용됩니다. 이것들은 모두 IO와 관련이 있습니다. 갑자기 스레드를 닫았을 때
제대로 닫히지 않으면 어떻게 해야 할까요? 당신은 단지 자신을 위해 버그를 만들고 있습니까? 아? !

그래서 이런 일에서 가장 중요한 것은 스레드를 종료하는 것이 아니라 스레드를 정리하는 것입니다.

해결책 · 1

더 좋은 방법은 각 스레드에 종료 요청 플래그를 두고 스레드에서 특정 간격으로 이를 확인하여 떠날 시간인지 확인하는 것입니다!

import threading

class StoppableThread(threading.Thread):
    """Thread class with a stop() method. The thread itself has to check
    regularly for the stopped() condition."""

    def __init__(self):
        super(StoppableThread, self).__init__()
        self._stop_event = threading.Event()

    def stop(self):
        self._stop_event.set()

    def stopped(self):
        return self._stop_event.is_set()

이 코드 부분에 표시된 것처럼 스레드를 종료하려면 명시적으로 stop() 함수를 호출하고, 스레드가 적절하게 종료될 때까지 기다려야 하는 Join() 함수를 사용해야 합니다. 스레드는 정기적으로 중지 플래그를 확인해야 합니다.

그러나 실제로 스레드를 종료해야 하는 몇 가지 사용 시나리오가 있습니다. 예를 들어 외부 라이브러리를 캡슐화했지만 외부 라이브러리 를 오랫동안 호출하여 프로세스를 중단하려는 경우입니다.

[권장: python 비디오 튜토리얼]

해결책 · 2

다음 해결 방법은 Python 스레드에서 예외 발생을 허용하는 것입니다(물론 몇 가지 제한 사항이 있습니다).

def _async_raise(tid, exctype):
    '''Raises an exception in the threads with id tid'''
    if not inspect.isclass(exctype):
        raise TypeError("Only types can be raised (not instances)")
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
                                                  ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        # "if it returns a number greater than one, you're in trouble,
        # and you should call it again with exc=NULL to revert the effect"
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
        raise SystemError("PyThreadState_SetAsyncExc failed")

class ThreadWithExc(threading.Thread):
    '''A thread class that supports raising exception in the thread from
       another thread.
    '''
    def _get_my_tid(self):
        """determines this (self's) thread id

        CAREFUL : this function is executed in the context of the caller
        thread, to get the identity of the thread represented by this
        instance.
        """
        if not self.isAlive():
            raise threading.ThreadError("the thread is not active")

        # do we have it cached?
        if hasattr(self, "_thread_id"):
            return self._thread_id

        # no, look for it in the _active dict
        for tid, tobj in threading._active.items():
            if tobj is self:
                self._thread_id = tid
                return tid

        # TODO: in python 2.6, there's a simpler way to do : self.ident

        raise AssertionError("could not determine the thread's id")

    def raiseExc(self, exctype):
        """Raises the given exception type in the context of this thread.

        If the thread is busy in a system call (time.sleep(),
        socket.accept(), ...), the exception is simply ignored.

        If you are sure that your exception should terminate the thread,
        one way to ensure that it works is:

            t = ThreadWithExc( ... )
            ...
            t.raiseExc( SomeException )
            while t.isAlive():
                time.sleep( 0.1 )
                t.raiseExc( SomeException )

        If the exception is to be caught by the thread, you need a way to
        check that your thread has caught it.

        CAREFUL : this function is executed in the context of the
        caller thread, to raise an excpetion in the context of the
        thread represented by this instance.
        """
        _async_raise( self._get_my_tid(), exctype )

댓글에 설명된 대로 이것은 "만병통치약"이 아닙니다. 왜냐하면 스레드가 Python 인터프리터 외부에서 사용 중이면 터미널 예외가 포착되지 않기 때문입니다~

이 코드를 사용하는 합리적인 방법은 다음과 같습니다. 스레드 특정 예외를 포착하고 정리 작업을 수행합니다. 이렇게 하면 작업을 종료하고 적절하게 정리할 수 있습니다.

해결책 · 3

인터럽트 방식과 비슷한 작업을 수행하려면 thread.join 방식을 사용할 수 있습니다.

join的原理就是依次检验线程池中的线程是否结束,没有结束就阻塞直到线程结束,如果结束则跳转执行下一个线程的join函数。

先看看这个:

1. 阻塞主进程,专注于执行多线程中的程序。

2. 多线程多join的情况下,依次执行各线程的join方法,前头一个结束了才能执行后面一个。

3. 无参数,则等待到该线程结束,才开始执行下一个线程的join。

4. 参数timeout为线程的阻塞时间,如 timeout=2 就是罩着这个线程2s 以后,就不管他了,继续执行下面的代码。
rrree

기본 조인 방법은 매개 변수 없음, 차단 모드이며 다른 스레드를 실행하기 전에 하위 스레드만 실행됩니다.

1. 두 개의 스레드가 동시에 시작되고 조인 기능이 실행됩니다.

2.waiting1 스레드가 3초 동안 실행(대기)된 후 종료됩니다.

3.waiting2 스레드가 8초 동안 실행(대기)된 후 작업이 종료됩니다.

4. Join 함수(메인 프로세스로 복귀) 실행이 종료됩니다.

이것은 스레드 실행이 시작된 후 수행되는 기본 조인 방법입니다. 조인 후 메인 스레드는 메인 스레드로 돌아가기 전에 하위 스레드가 완료될 때까지 기다려야 합니다.

timeout 매개변수인 Join 매개변수를 2, 즉 Join(2)로 변경하면 다음과 같은 결과가 나옵니다.

  1. 두 개의 스레드가 동시에 시작되고, Join 함수는 다음과 같습니다. 실행됩니다.

  2. wating1 스레드는 3초 동안 실행(대기)한 후 완료되었습니다.

  3. 조인 종료(2가 2개, 총 4가, 36-32=4, 맞음).

  4. waiting2 스레드가 Join에서 지정한 대기 시간(4초) 내에 완료되지 않아 나중에 실행을 완료했습니다.

join(2)은: 서브 스레드에 2초의 시간을 주고, 각 2초가 끝나면 떠날 것이며 조금도 걱정하지 않을 것입니다!

위 내용은 파이썬에서 스레드를 종료하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.