>  기사  >  백엔드 개발  >  Python에서 스레드, 코루틴 및 프로세스를 강제로 닫는 방법은 무엇입니까?

Python에서 스레드, 코루틴 및 프로세스를 강제로 닫는 방법은 무엇입니까?

WBOY
WBOY앞으로
2023-04-20 14:34:061660검색

멀티스레딩

우선 스레드를 종료할 때 우리는 하위 스레드 실행의 루프 조건에 조건을 설정하는 방법을 자주 사용합니다. 하위 스레드를 종료해야 할 경우 조건을 설정합니다. 이때 하위 스레드는 적극적으로 종료되지만 하위 스레드가 차단되면 루프에서 조건이 판단되지 않으며 차단 시간이 불확실하므로 스레드를 재활용할 가능성이 없습니다. 이때 필요한 방법은 다음과 같습니다.

데몬 스레드:

스레드를 데몬 스레드로 설정하면 프로세스가 종료될 때 이 스레드가 중요하지 않다는 의미입니다. 이 스레드가 종료될 때까지 기다리십시오.
메인 스레드가 종료 시 해당 하위 스레드가 완료될 때까지 기다릴 필요가 없다면 이러한 스레드의 데몬 속성을 설정하세요. 즉, 스레드가 시작(thread.start())되기 전에 setDeamon() 함수를 호출하여 스레드의 데몬 플래그를 설정합니다. (thread.setDaemon(True))은 이 스레드가 "중요하지 않음"을 의미합니다.

종료하기 전에 하위 스레드가 완료될 때까지 기다리려면 아무 작업도 수행하지 마세요. , 또는 thread.setDaemon(False)을 명시적으로 호출하여 데몬 값을 false로 설정합니다. 새 하위 스레드는 상위 스레드의 데몬 플래그를 상속합니다. 데몬이 아닌 스레드가 모두 종료된 후, 즉 프로세스에 데몬이 아닌 스레드가 없는 경우 전체 Python이 종료됩니다.

즉, 하위 스레드는 데몬이 아닌 스레드이고, 메인 스레드는 즉시 종료되지 않습니다.

import threading
import time
import gc
import datetime

def circle():
    print("begin")
    try:
        while True:
            current_time = datetime.datetime.now()
            print(str(current_time) + ' circle.................')
            time.sleep(3)
    except Exception as e:
        print('error:',e)
    finally:
        print('end')


if __name__ == "__main__":
   t = threading.Thread(target=circle)
   t.setDaemon(True)
   t.start()
   time.sleep(1)
   # stop_thread(t)
   # print('stoped threading Thread') 
   current_time = datetime.datetime.now()
   print(str(current_time) + ' stoped after') 
   gc.collect()
   while True:
      time.sleep(1)
      current_time = datetime.datetime.now()
      print(str(current_time) + ' end circle')

메인 스레드에 의해 제어됩니까?

하위 스레드 종료를 완료하려면 데몬 스레드를 종료하기 위해 메인 스레드가 필요합니다 다음은 코드이며, 메인 스레드가 종료되어야 하는지 확인하기 위해 이를 하나의 레이어로 캡슐화합니다

def Daemon_thread():
   circle_thread= threading.Thread(target=circle)
#    circle_thread.daemon = True
   circle_thread.setDaemon(True)
   circle_thread.start()   
   while running:
        print('running:',running) 
        time.sleep(1)
   print('end..........') 


if __name__ == "__main__":
    t = threading.Thread(target=Daemon_thread)
    t.start()   
    time.sleep(3)
    running = False
    print('stop running:',running) 
    print('stoped 3') 
    gc.collect()
    while True:
        time.sleep(3)
        print('stoped circle')

메인 함수 실행을 교체합니다. 중지된 3 플래그를 인쇄한 후에도 원 스레드가 여전히 남아 있음을 확인합니다. 실행을 계속합니다.

결론: 메인 스레드는 신호 처리를 담당합니다. 이를 활성화해야만 신호가 올바르게 처리될 수 있습니다.

Python 스레드에서 예외 발생

PyThreadState_SetAsyncExc를 사용하면 대부분의 경우 스레드에서 직접 종료할 수 있지만 PyThreadState_SetAsyncExc 메서드는 스레드 종료에 대한 "계획"만 실행합니다. 특히 외부 C 라이브러리를 실행할 때 스레드를 종료하지 않습니다. sleep(100)을 시도하여 하나를 죽이십시오. 100초 후에 "죽게" 됩니다. while 플래그: ->flag = False 방식과 동일하게 작동합니다.

그래서 하위 스레드에 슬립과 같은 차단 기능이 있는 경우 슬립 프로세스 중에 하위 스레드가 응답할 수 없으며 메인 스레드에 의해 캡처되므로 하위 스레드를 취소할 수 없습니다. 실제로 스레드가 휴면 상태일 때 async_raise 함수를 직접 사용하여 스레드를 종료하는 것은 불가능합니다. 스레드가 Python 인터프리터 외부에서 사용 중이면 인터럽트를 포착하지 못하기 때문입니다

샘플 코드:

import ctypes
import inspect
import threading
import time
import gc
import datetime

def async_raise(tid, exctype):
   """raises the exception, performs cleanup if needed"""
   tid = ctypes.c_long(tid)
   if not inspect.isclass(exctype):
      exctype = type(exctype)
   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, None)
      raise SystemError("PyThreadState_SetAsyncExc failed")
      
def stop_thread(thread):
   async_raise(thread.ident, SystemExit)
   
def circle():
    print("begin")
    try:
        while True:
            current_time = datetime.datetime.now()
            print(str(current_time) + ' circle.................')
            time.sleep(3)
    except Exception as e:
        print('error:',e)
    finally:
        print('end')

if __name__ == "__main__":
   t = threading.Thread(target=circle)
   t.start()
   time.sleep(1)
   stop_thread(t)
   print('stoped threading Thread') 
   current_time = datetime.datetime.now()
   print(str(current_time) + ' stoped after') 
   gc.collect()
   while True:
      time.sleep(1)
      current_time = datetime.datetime.now()
      print(str(current_time) + ' end circle')

signal .pthread_kill 작업:

이것은 Unix의 pthread kill 작업에 가장 가깝습니다. 인터넷에서 몇 가지 사용법을 본 적이 있지만 확인했을 때 이 라이브러리에서는 사용법을 찾지 못했습니다. python의 공식 시그널 설명 문서를 보니 3.3버전이 새로 나오네요..함수는 python3.10을 사용하고 있는데, 이후 버전에서는 pthread_kill이 없어질 수도 있습니다.

Python에서 스레드, 코루틴 및 프로세스를 강제로 닫는 방법은 무엇입니까?온라인에서 본 샘플 코드인데 실행이 안되네요. 사용법 아시는 분 계시면 소통 가능합니다.

from signal import pthread_kill, SIGTSTP
from threading import Thread
from itertools import count
from time import sleep

def target():
    for num in count():
        print(num)
        sleep(1)

thread = Thread(target=target)
thread.start()
sleep(5)
signal.pthread_kill(thread.ident, SIGTSTP)

Multiprocessing

multiprocessing은 스레딩 모듈과 유사한 API를 사용하여 프로세스 생성을 지원하는 패키지입니다. 다중 처리 패키지는 로컬 및 원격 동시 작업을 모두 제공하여 스레드 대신 하위 프로세스를 사용하여 전역 인터프리터 잠금을 효과적으로 우회합니다. 따라서 멀티프로세싱 모듈을 사용하면 프로그래머는 특정 시스템에서 다중 프로세서를 최대한 활용할 수 있습니다.

다중 프로세스 라이브러리가 사용되며, 내부 함수 종료를 호출하여 릴리스하는 데 도움을 줄 수 있습니다. 예를 들어, t.terminate()는 하위 프로세스를 강제로 종료할 수 있습니다.

그러나 다중 프로세스 데이터를 사용하는 상호 작용 방법은 더 번거롭습니다. 하위 프로세스와 상위 프로세스 간의 데이터 상호 작용에는 공유 메모리, 파이프 또는 메시지 큐를 사용해야 합니다.

샘플 코드는 다음과 같습니다.

import time
import gc
import datetime
import multiprocessing

def circle():
    print("begin")
    try:
        while True:
            current_time = datetime.datetime.now()
            print(str(current_time) + ' circle.................')
            time.sleep(3)
    except Exception as e:
        print('error:',e)
    finally:
        print('end')


if __name__ == "__main__":
    t = multiprocessing.Process(target=circle, args=())
    t.start()
    # Terminate the process
    current_time = datetime.datetime.now()
    print(str(current_time) + ' stoped before') 
    time.sleep(1)
    t.terminate()  # sends a SIGTERM
    current_time = datetime.datetime.now()
    print(str(current_time) + ' stoped after') 
    gc.collect()
    while True:
        time.sleep(3)
        current_time = datetime.datetime.now()
        print(str(current_time) + ' end circle')

다중 코루틴

코루틴은 멀티태스킹을 달성하는 또 다른 방법이며 일반적으로 단일 프로세스 및 단일 프로세스에서 실행됩니다. . 자체 CPU 컨텍스트를 갖고 있기 때문에 간단한 이벤트 루프를 통해 작업을 전환할 수 있는데, 이는 프로세스와 스레드 간 전환이 운영체제에 의해 수행되기 때문에 프로세스와 스레드 간 전환보다 더 효율적이다.

Python은 주로 두 가지 라이브러리에 의존하여 코루틴을 구현합니다: asyncio(asyncio는 Python 3.4에서 도입된 표준 라이브러리로, 코루틴 비동기 IO에 대한 지원이 직접 내장되어 있습니다. asyncio의 프로그래밍 모델은 본질적으로 메시지 루프입니다. 일반적으로 먼저 코루틴 함수(또는 작업)를 정의하고 asyncio 모듈에서 이벤트 루프 루프를 얻은 다음 실행해야 하는 코루틴 작업(또는 작업 목록)을 루프에 던져 실행함으로써 비동기 IO를 구현하고 gevent(Gevent) gevent를 통해 동시 동기 또는 비동기 프로그래밍을 쉽게 구현할 수 있는 타사 라이브러리입니다. gevent에서 사용되는 주요 모드는 C 확장 모듈 형태로 Python에 연결되는 경량 코루틴인 Greenlet입니다.

由于asyncio已经成为python的标准库了无需pip安装即可使用,这意味着asyncio作为Python原生的协程实现方式会更加流行。本文仅会介绍asyncio模块的退出使用。

使用协程取消,有两个重要部分:第一,替换旧的休眠函数为多协程的休眠函数;第二取消使用cancel()函数。

其中cancel() 返回值为 True 表示 cancel 成功。

示例代码如下:创建一个coroutine,然后调用run_until_complete()来初始化并启动服务器来调用main函数,判断协程是否执行完成,因为设置的num协程是一个死循环,所以一直没有执行完,如果没有执行完直接使用 cancel()取消掉该协程,最后执行成功。

import asyncio
import time


async def num(n):
    try:
        i = 0
        while True:
            print(f'i={i} Hello')
            i=i+1
            # time.sleep(10)
            await asyncio.sleep(n*0.1)
        return n
    except asyncio.CancelledError:
        print(f"数字{n}被取消")
        raise


async def main():
    # tasks = [num(i) for i in range(10)]
    tasks = [num(10)]
    complete, pending = await asyncio.wait(tasks, timeout=0.5)
    for i in complete:
        print("当前数字",i.result())
    if pending:
        print("取消未完成的任务")
        for p in pending:
            p.cancel()


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
    finally:
        loop.close()

위 내용은 Python에서 스레드, 코루틴 및 프로세스를 강제로 닫는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제