Heim >Backend-Entwicklung >Python-Tutorial >Mit welcher Methode können Threads, Coroutinen und Prozesse in Python zwangsweise geschlossen werden?

Mit welcher Methode können Threads, Coroutinen und Prozesse in Python zwangsweise geschlossen werden?

WBOY
WBOYnach vorne
2023-04-20 14:34:061698Durchsuche

Multithreading

Zuallererst verwenden wir beim Beenden eines Threads häufig eine Methode: Festlegen einer Bedingung in der Schleifenbedingung der Sub-Thread-Ausführung. Wenn wir den Sub-Thread verlassen müssen, legen Sie die Bedingung fest. Zu diesem Zeitpunkt wird der untergeordnete Thread aktiv beendet. Wenn jedoch der untergeordnete Thread blockiert ist, werden in der Schleife keine Bedingungen beurteilt und die Blockierungszeit ist ungewiss. Wir haben keine Hoffnung, den Thread wiederzuverwenden. Zu diesem Zeitpunkt sind die folgenden Methoden erforderlich:

Daemon-Thread:

Wenn Sie einen Thread als Daemon-Thread festlegen, bedeutet dies, dass Sie sagen, dass dieser Thread nicht wichtig ist. Wenn der Prozess beendet wird, ist dies nicht erforderlich warte, bis dieser Thread beendet ist.
Wenn Ihr Hauptthread beim Beenden nicht auf den Abschluss dieser untergeordneten Threads warten muss, legen Sie die Daemon-Attribute dieser Threads fest. Das heißt, bevor der Thread startet (thread.start()), rufen Sie die Funktion setDeamon() auf, um das Daemon-Flag des Threads zu setzen. (thread.setDaemon(True)) bedeutet, dass dieser Thread „nicht wichtig“ ist.

Wenn Sie mit dem Beenden warten möchten, bis der untergeordnete Thread abgeschlossen ist, dann unternehmen Sie nichts. , oder rufen Sie explizit thread.setDaemon(False) auf, um den Daemon-Wert auf false zu setzen. Der neue untergeordnete Thread erbt das Daemon-Flag des übergeordneten Threads. Das gesamte Python wird beendet, nachdem alle Nicht-Daemon-Threads beendet wurden, d. h. wenn im Prozess keine Nicht-Daemon-Threads vorhanden sind.

Das heißt, der untergeordnete Thread ist ein Nicht-Deamon-Thread und der Hauptthread wird nicht sofort beendet

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')

Wird er vom Hauptthread gesteuert?

Der Daemon-Thread muss den Haupt-Thread beenden, um den Unter-Thread-Exit abzuschließen. Das Folgende ist der Code und kapselt ihn dann in einer Ebene, um zu überprüfen, ob der Haupt-Thread beendet werden muss.

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')

Ersetzen Sie die Ausführung der Hauptfunktion und stellen Sie fest, dass nach dem Drucken der Stopp-3-Flagge der Kreisthread immer noch vorhanden ist. Fahren Sie mit der Ausführung fort.

Fazit: Der Hauptthread ist für die Verarbeitung von Signalen verantwortlich. Nur wenn sichergestellt wird, dass er aktiv ist, kann das Signal korrekt verarbeitet werden.

Im Python-Thread ausgelöste Ausnahme

Obwohl die Verwendung von PyThreadState_SetAsyncExc in den meisten Fällen unseren direkten Ausstieg aus dem Thread erfüllen kann, führt die PyThreadState_SetAsyncExc-Methode nur den „Plan“ für den Thread-Ausstieg aus. Der Thread wird dadurch nicht beendet, insbesondere wenn er eine externe C-Bibliothek ausführt. Versuchen Sie Sleep(100) auf Ihre Art, einen zu töten. Es wird nach 100 Sekunden „getötet“. while flag: Es funktioniert genauso wie die Methode ->flag = False.

Wenn also der Sub-Thread über Blockierungsfunktionen wie Ruhezustand verfügt, kann der Sub-Thread während des Schlafvorgangs nicht reagieren und wird vom Haupt-Thread erfasst, sodass der Sub-Thread nicht abgebrochen werden kann. Wenn der Thread schläft, ist es tatsächlich nicht möglich, die Funktion async_raise direkt zum Beenden des Threads zu verwenden, da der Thread, wenn er außerhalb des Python-Interpreters beschäftigt ist, den Interrupt nicht abfängt. Beispielcode:

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-Operation:

Dies kommt der pthread-Kill-Operation in Unix am nächsten. Ich habe einige Verwendungen im Internet gesehen, aber ich habe die Verwendung in dieser Bibliothek nicht gefunden

Dies ist die Beschreibung in Offizielles Signalerklärungsdokument von Python. Ich habe gesehen, dass es sich um die neue Version 3.3 handelt. Ich verwende Python3.10 und es gibt kein pthread_kill. Es kann in nachfolgenden Versionen entfernt werden.

Dies ist ein Beispielcode, den ich online gesehen habe, aber er kann nicht ausgeführt werden. Wenn jemand weiß, wie man ihn verwendet, können Sie mitteilen. Mit welcher Methode können Threads, Coroutinen und Prozesse in Python zwangsweise geschlossen werden?

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 ist ein Paket, das Spawning-Prozesse mithilfe einer API unterstützt, die dem Threading-Modul ähnelt. Das Multiprocessing-Paket bietet sowohl lokale als auch entfernte gleichzeitige Operationen und umgeht effektiv die globale Interpretersperre, indem es untergeordnete Prozesse anstelle von Threads verwendet. Daher ermöglicht das Multiprocessing-Modul Programmierern, die Vorteile mehrerer Prozessoren auf einer bestimmten Maschine voll auszunutzen.

Es werden Multiprozessbibliotheken verwendet, und wir können ihre interne Funktion „terminate“ aufrufen, um uns bei der Freigabe zu helfen. Beispielsweise kann t.terminate() das Beenden des untergeordneten Prozesses erzwingen.

Die Interaktionsmethode mit Multiprozessdaten ist jedoch umständlicher. Für die Dateninteraktion zwischen dem untergeordneten Prozess und dem übergeordneten Prozess muss ein gemeinsamer Speicher, eine Pipe oder eine Nachrichtenwarteschlange verwendet werden.

Der Beispielcode lautet wie folgt:

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')

Mehrere Coroutinen

Coroutinen werden auch als Mikro-Threads bezeichnet. Sie sind kleinere Ausführungseinheiten als Threads und werden im Allgemeinen in einzelnen Prozessen ausgeführt . im Thread. Da es über einen eigenen CPU-Kontext verfügt, kann es Aufgaben über eine einfache Ereignisschleife wechseln, was effizienter ist als das Umschalten zwischen Prozessen und Threads, da das Umschalten zwischen Prozessen und Threads vom Betriebssystem durchgeführt wird.

Python verlässt sich hauptsächlich auf zwei Bibliotheken, um Coroutinen zu implementieren: Asyncio (Asyncio ist eine mit Python 3.4 eingeführte Standardbibliothek, die direkt integrierte Unterstützung für asynchrone Coroutinen-E/A bietet. Das Programmiermodell von Asyncio ist im Wesentlichen eine Nachrichtenschleife. Wir im Allgemeinen Zuerst Definieren Sie eine Coroutine-Funktion (oder -Aufgabe), rufen Sie die Ereignisschleifenschleife vom Asyncio-Modul ab und werfen Sie dann die Coroutine-Aufgabe (oder Aufgabenliste), die ausgeführt werden muss, zur Ausführung in die Schleife, wodurch asynchrone E / A (E / A) und Gevent (Gevent) realisiert werden ist eine Bibliothek eines Drittanbieters, die problemlos gleichzeitige synchrone oder asynchrone Programmierung über gevent implementieren kann. Der in gevent verwendete Hauptmodus ist Greenlet, eine leichtgewichtige Coroutine, die in Form eines C-Erweiterungsmoduls mit Python verbunden ist.

由于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()

Das obige ist der detaillierte Inhalt vonMit welcher Methode können Threads, Coroutinen und Prozesse in Python zwangsweise geschlossen werden?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen