Maison  >  Article  >  développement back-end  >  Quelle est la méthode pour fermer de force les threads, les coroutines et les processus en Python ?

Quelle est la méthode pour fermer de force les threads, les coroutines et les processus en Python ?

WBOY
WBOYavant
2023-04-20 14:34:061660parcourir

Multi-threading

Tout d'abord, lors de la sortie d'un thread, nous utilisons souvent une méthode : définir une condition dans la condition de boucle de l'exécution du sous-thread. Lorsque nous devons quitter le sous-thread, définissez la condition. À ce stade, le sous-thread se fermera activement, mais lorsque le thread enfant est bloqué, aucune condition n'est jugée dans la boucle et le temps de blocage est incertain, nous n'avons aucun espoir de recycler le thread. À l'heure actuelle, les méthodes suivantes sont nécessaires :

Thread démon :

Si vous définissez un thread comme thread démon, cela signifie que vous dites que ce thread n'est pas important. Lorsque le processus se termine, vous n'avez pas besoin de le faire. attendez que ce fil quitte.
Si votre thread principal n'a pas besoin d'attendre la fin de ces threads enfants à sa sortie, définissez les attributs démon de ces threads. Autrement dit, avant le démarrage du thread (thread.start()), appelez la fonction setDeamon() pour définir l'indicateur de démon du thread. (thread.setDaemon(True)) signifie que ce fil n'est "pas important".

Si vous souhaitez attendre que le fil de discussion enfant soit terminé avant de quitter, ne faites rien. , ou appelez explicitement thread.setDaemon(False) pour définir la valeur du démon sur false. Le nouveau thread enfant héritera de l'indicateur démon du thread parent. L'intégralité de Python se terminera après la sortie de tous les threads non-démons, c'est-à-dire lorsqu'il n'y a aucun thread non-démon dans le processus.

C'est-à-dire que le thread enfant est un thread non démon, et le thread principal ne se ferme pas immédiatement

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

Est-il contrôlé par le thread principal ?

Le thread démon a besoin que le thread principal se termine pour terminer la sortie du sous-thread Ce qui suit est le code, puis l'encapsule sur une couche pour vérifier si le thread principal doit quitter

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

Remplacez l'exécution de la fonction principale. et constatez qu'après avoir imprimé le drapeau arrêté 3, le fil circulaire est toujours là. Continuez l'exécution.

Conclusion : le thread principal est responsable du traitement des signaux. Ce n'est qu'en s'assurant qu'il est vivant que le signal peut être traité correctement.

Exception levée dans le thread Python

Bien que l'utilisation de PyThreadState_SetAsyncExc puisse satisfaire notre sortie directe du thread dans la plupart des cas ; la méthode PyThreadState_SetAsyncExc exécute uniquement le "plan" pour que le thread se termine. Cela ne tue pas le thread, surtout lorsqu'il exécute une bibliothèque C externe. Essayez sleep(100) pour en tuer un. Il sera « tué » après 100 secondes. while flag : Cela fonctionne de la même manière que la méthode ->flag = False.

Ainsi, lorsque le sous-thread a des fonctions de blocage telles que la mise en veille, pendant le processus de mise en veille, le sous-thread ne peut pas répondre et sera capturé par le thread principal, ce qui rendra impossible l'annulation du sous-thread. En fait, lorsque le thread est en veille, il n'est pas possible d'utiliser directement la fonction async_raise pour tuer le thread, car si le thread est occupé en dehors de l'interpréteur Python, il n'attrapera pas l'interruption

Exemple de code :

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 Opération .pthread_kill :

C'est l'opération la plus proche de l'opération pthread kill sous Unix. J'ai vu quelques utilisations sur Internet, mais je n'ai pas trouvé l'utilisation dans cette bibliothèque lorsque je l'ai vérifiée

C'est la description dans le. document officiel d'explication du signal de python. J'ai vu qu'il s'agit de la nouvelle version 3.3 de la fonction, j'utilise python3.10 et il n'y a pas de pthread_kill. Elle peut être supprimée dans les versions ultérieures.

Quelle est la méthode pour fermer de force les threads, les coroutines et les processus en Python ?

Voici un exemple de code que j'ai vu en ligne, mais il ne peut pas être exécuté. Si quelqu'un sait comment l'utiliser, vous pouvez communiquer.

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 est un package qui prend en charge les processus de génération à l'aide d'une API similaire au module de threading. Le package multitraitement fournit des opérations simultanées locales et distantes, contournant efficacement le verrouillage global de l'interpréteur en utilisant des processus enfants au lieu de threads. Par conséquent, le module multitraitement permet aux programmeurs de tirer pleinement parti de plusieurs processeurs sur une machine donnée.

Des bibliothèques multiprocessus sont utilisées, et nous pouvons appeler sa fonction interne terminate pour nous aider à la publier. Par exemple, t.terminate() peut forcer la fermeture du processus enfant.

Cependant, la méthode d'interaction utilisant des données multi-processus est plus lourde. La mémoire partagée, le canal ou la file d'attente de messages doivent être utilisés pour l'interaction des données entre le processus enfant et le processus parent.

L'exemple de code est le suivant :

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

Coroutines multiples

Les coroutines sont également appelées micro-threads. Elles sont une autre façon de réaliser le multitâche. Ce sont des unités d'exécution plus petites que les threads et s'exécutent généralement dans des processus uniques et des processus uniques. .sur le fil. Parce qu'il possède son propre contexte CPU, il peut changer de tâche via une simple boucle d'événements, ce qui est plus efficace que la commutation entre les processus et les threads, car la commutation entre les processus et les threads est effectuée par le système d'exploitation.

Python s'appuie principalement sur deux bibliothèques pour implémenter les coroutines : asyncio (asyncio est une bibliothèque standard introduite à partir de Python 3.4, qui a directement un support intégré pour les E/S asynchrones coroutine. Le modèle de programmation d'asyncio est essentiellement une boucle de messages. Nous d'abord définir une fonction (ou tâche) coroutine, obtenir la boucle de boucle d'événement à partir du module asyncio, puis lancer la tâche coroutine (ou liste de tâches) qui doit être exécutée dans la boucle pour exécution, réalisant ainsi des IO asynchrones) et gevent (Gevent est une bibliothèque tierce qui peut facilement implémenter une programmation synchrone ou asynchrone simultanée via gevent. Le mode principal utilisé dans gevent est Greenlet, qui est une coroutine légère connectée à Python sous la forme d'un module d'extension C.

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer