Maison développement back-end Tutoriel Python Ne forcez pas la suppression des threads Python

Ne forcez pas la suppression des threads Python

Feb 28, 2017 am 09:06 AM

Avant-propos :

N'essayez pas de tuer un thread python par la force, c'est déraisonnable en termes de conception de service. Le multithreading est utilisé pour la concurrence collaborative des tâches. Si vous utilisez la force pour tuer des threads, il existe un risque élevé de bogues inattendus. N'oubliez pas que la ressource de verrouillage ne sera pas libérée car le thread se termine !

Nous pouvons donner deux exemples courants :

1. Le thread A a obtenu le verrou car il a été tué de force et n'a pas réussi à libérer la ressource de verrouillage à temps avec release() , alors tous les threads seront bloqué dans l’acquisition de ressources, ce qui est un scénario d’impasse typique.

2. Dans un scénario production-consommateur courant, le consommateur obtient les tâches de la file d'attente des tâches, mais ne remet pas la tâche en cours dans la file d'attente après avoir été tué, ce qui entraîne une perte de données.

Voici les façons de terminer les threads en Java et Python :

Java dispose de trois méthodes pour terminer les threads :

1. indicateur de sortie pour que le thread se termine normalement, c'est-à-dire que le thread se termine lorsque la méthode run est terminée.
2. Utilisez la méthode stop pour terminer de force le thread (non recommandé, car l'arrêt est la même chose que la suspension et la reprise, et des résultats imprévisibles peuvent survenir).
3. Utilisez la méthode d'interruption pour interrompre le fil.

Python peut avoir deux méthodes :

1. Marque de sortie
2 Utilisez des ctypes pour tuer le fil de force

Non. important Dans un environnement Python ou Java, le moyen idéal pour arrêter et quitter un thread est de laisser le thread se suicider. Ce qu'on appelle le suicide du thread signifie que vous lui donnez un indicateur et qu'il quitte le thread.

Ci-dessous, nous utiliserons diverses méthodes pour tester la situation anormale d'arrêt du thread python. Nous examinons tous les threads d'exécution d'un processus. Le processus utilise des ressources de contrôle et le thread est utilisé comme unité de planification. Pour être planifié pour l'exécution, un processus doit avoir un thread par défaut. le processus.

ps -mp 31449 -o THREAD,tid
 
USER   %CPU PRI SCNT WCHAN USER SYSTEM  TID
root   0.0  -  - -     -   -   -
root   0.0 19  - poll_s  -   - 31449
root   0.0 19  - poll_s  -   - 31450
Copier après la connexion

Après avoir obtenu tous les threads du processus, nous savons grâce à strace que 31450 est l'ID de thread qui doit être tué lorsque nous tuons, il apparaîtra Une situation où l'ensemble du processus se bloque. Dans un environnement multithread, le signal généré est transmis à l'ensemble du processus. De manière générale, tous les threads ont la possibilité de recevoir ce signal. Le processus exécute la fonction de traitement du signal dans le contexte du thread qui reçoit le signal. Difficile de le savoir. En d’autres termes, le signal sera envoyé aléatoirement à un thread du processus.

strace -p <span style="font-size:14px;line-height:21px;">31450</span> Process <span style="font-size:14px;line-height:21px;">31450</span> attached - interrupt to quit
select(0, NULL, NULL, NULL, {0, 320326}) = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0})   = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0})   = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0})   = ? ERESTARTNOHAND (To be restarted)
--- SIGTERM (Terminated) @ 0 (0) ---
Process <span style="font-size:14px;line-height:21px;">31450</span> detached
Copier après la connexion

Le problème ci-dessus est en fait cohérent avec la description de pthread. Lorsque nous ajoutons la fonction de traitement du signal au code python, la fonction de rappel peut empêcher l'ensemble du processus de se terminer. Le problème survient alors. La fonction signal ne peut pas identifier le thread que vous souhaitez tuer. certain fil. Bien que vous envoyiez le signal à l'ID de thread 31450, l'accepteur de signal est l'un des processus auquel il appartient. De plus, les paramètres transmis à la fonction de traitement du signal sont uniquement le numéro de signal et la pile de signaux, qui sont facultatifs.

Après l'ajout du traitement du signal, le processus ne se terminera pas

select(0, NULL, NULL, NULL, {1, 0})   = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0})   = ? ERESTARTNOHAND (To be restarted)
--- SIGTERM (Terminated) @ 0 (0) ---
rt_sigreturn(0xffffffff)        = -1 EINTR (Interrupted system call)
select(0, NULL, NULL, NULL, {1, 0})   = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0})   = 0 (Timeout)
Copier après la connexion

Si vous souhaitez tuer un thread à partir d'un externe notification , vous pouvez alors créer et utiliser des services rpc, ou communiquer par d'autres moyens, mais les signaux ne le peuvent pas, car ils ne peuvent pas transmettre plus d'informations.

Les threads Python ne sont pas simulés, ce sont de vrais threads du noyau. Le noyau appelle la méthode pthread, mais la couche supérieure de Python ne fournit pas de méthode pour fermer le thread, nous devons donc le comprendre nous-mêmes. Il est fortement recommandé d'utiliser des méthodes d'événement ou de bit d'indicateur personnalisé. Si vous devez tuer le thread de force, vous pouvez utiliser la méthode python ctypes PyThreadState SetAsyncExc pour forcer la sortie, ce qui n'aura aucun impact sur le service Python en cours d'exécution.

Le principe de mise en œuvre de cette fonction est relativement simple. En fait, il s'agit de définir un indicateur dans la machine virtuelle python, puis la machine virtuelle exécutera une exception pour annuler le thread virtuel. la machine vous aidera à faire un essai du cache. N'oubliez pas de ne pas tuer un thread en Python en externe. Bien que vous puissiez trouver l'ID du thread via les ctypes, le tuer directement tuera l'ensemble du processus.

Le code suivant est un exemple d'utilisation de ctypes pour tuer un fil de discussion. Il n'est pas recommandé car il est trop grossier.

import ctypes
 
def terminate_thread(thread):
  if not thread.isAlive():
    return
 
  exc = ctypes.py_object(SystemExit)
  res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
    ctypes.c_long(thread.ident), exc)
  if res == 0:
    raise ValueError("nonexistent thread id")
  elif res > 1:
    ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
    raise SystemError("PyThreadState_SetAsyncExc failed")
Copier après la connexion

<🎜. >

Jetons un bref coup d'œil au code source de PyThreadState. Bref, le mode exception du thread est déclenché. Ceux qui sont intéressés peuvent lire le design de python pystate.c et le partager avec quelques vidéos sur YouTube.


 int
PyThreadState_SetAsyncExc(long id, PyObject *exc) {
  PyInterpreterState *interp = GET_INTERP_STATE();
  ...
  HEAD_LOCK();
  for (p = interp->tstate_head; p != NULL; p = p->next) {
    if (p->thread_id == id) {
      从链表里找到线程的id,避免死锁,我们需要释放head_mutex。
      PyObject *old_exc = p->async_exc;
      Py_XINCREF(exc); #增加该对象的引用数
      p->async_exc = exc; # 更为exc模式
      HEAD_UNLOCK();
      Py_XDECREF(old_exc); # 因为要取消,当然也就递减引用
      ...
      return 1; #销毁线程成功
    }
  }
  HEAD_UNLOCK();
  return 0;
}
Copier après la connexion

Le pthread posix natif peut utiliser ptread_cancel(tid) pour terminer le fil enfant dans le fil principal. Cependant, la bibliothèque de threads de Python ne prend pas en charge cela. La raison est que nous ne devons pas forcer la fin d'un thread. Cela entraînerait de nombreux dangers cachés et le thread devrait être autorisé à se terminer lui-même. Par conséquent, en Python, la méthode recommandée consiste à parcourir un sous-thread pour déterminer un indicateur, à modifier l'indicateur dans le thread principal et à se terminer lorsque le sous-thread lit le changement d'indicateur.

Semblable à cette logique :

def consumer_threading():
 t1_stop= threading.Event()
 t1 = threading.Thread(target=thread1, args=(1, t1_stop))
 
 t2_stop = threading.Event()
 t2 = threading.Thread(target=thread2, args=(2, t2_stop))
 
 time.sleep(duration)
 #stop the thread2
 t2_stop.set()
 
def thread1(arg1, stop_event):
 while(not stop_event.is_set()):
   #similar to time.sleep()
   stop_event.wait(time)
   pass
 
 
def thread2(arg1, stop_event):
 while(not stop_event.is_set()):
   stop_event.wait(time)
   pass
Copier après la connexion

Un bref résumé, bien que nous puissions utiliser des pystats dans les ctypes pour contrôler les threads, cette méthode d'interruption brutale des threads est déraisonnable. S'il vous plaît, utilisez le mode suicide ! Que se passe-t-il si votre thread bloque io et ne peut pas déterminer l'événement ? Votre programme doit être optimisé. Au moins, il doit avoir un délai d'attente actif au niveau de la couche IO du réseau pour éviter d'être bloqué à tout moment.

Pour plus d'articles sur la non-utilisation de méthodes forcées pour tuer les threads python, veuillez faire attention au site Web PHP chinois !

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Comment déverrouiller tout dans Myrise
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment résoudre le problème des autorisations rencontré lors de la visualisation de la version Python dans le terminal Linux? Comment résoudre le problème des autorisations rencontré lors de la visualisation de la version Python dans le terminal Linux? Apr 01, 2025 pm 05:09 PM

Solution aux problèmes d'autorisation Lors de la visualisation de la version Python dans Linux Terminal Lorsque vous essayez d'afficher la version Python dans Linux Terminal, entrez Python ...

Comment enseigner les bases de la programmation novice en informatique dans le projet et les méthodes axées sur les problèmes dans les 10 heures? Comment enseigner les bases de la programmation novice en informatique dans le projet et les méthodes axées sur les problèmes dans les 10 heures? Apr 02, 2025 am 07:18 AM

Comment enseigner les bases de la programmation novice en informatique dans les 10 heures? Si vous n'avez que 10 heures pour enseigner à l'informatique novice des connaissances en programmation, que choisissez-vous d'enseigner ...

Comment copier efficacement la colonne entière d'une dataframe dans une autre dataframe avec différentes structures dans Python? Comment copier efficacement la colonne entière d'une dataframe dans une autre dataframe avec différentes structures dans Python? Apr 01, 2025 pm 11:15 PM

Lorsque vous utilisez la bibliothèque Pandas de Python, comment copier des colonnes entières entre deux frames de données avec différentes structures est un problème courant. Supposons que nous ayons deux dats ...

Comment éviter d'être détecté par le navigateur lors de l'utilisation de Fiddler partout pour la lecture de l'homme au milieu? Comment éviter d'être détecté par le navigateur lors de l'utilisation de Fiddler partout pour la lecture de l'homme au milieu? Apr 02, 2025 am 07:15 AM

Comment éviter d'être détecté lors de l'utilisation de FiddlereVerywhere pour les lectures d'homme dans le milieu lorsque vous utilisez FiddlereVerywhere ...

Que sont les expressions régulières? Que sont les expressions régulières? Mar 20, 2025 pm 06:25 PM

Les expressions régulières sont des outils puissants pour la correspondance des motifs et la manipulation du texte dans la programmation, améliorant l'efficacité du traitement de texte sur diverses applications.

Comment Uvicorn écoute-t-il en permanence les demandes HTTP sans servir_forever ()? Comment Uvicorn écoute-t-il en permanence les demandes HTTP sans servir_forever ()? Apr 01, 2025 pm 10:51 PM

Comment Uvicorn écoute-t-il en permanence les demandes HTTP? Uvicorn est un serveur Web léger basé sur ASGI. L'une de ses fonctions principales est d'écouter les demandes HTTP et de procéder ...

Comment créer dynamiquement un objet via une chaîne et appeler ses méthodes dans Python? Comment créer dynamiquement un objet via une chaîne et appeler ses méthodes dans Python? Apr 01, 2025 pm 11:18 PM

Dans Python, comment créer dynamiquement un objet via une chaîne et appeler ses méthodes? Il s'agit d'une exigence de programmation courante, surtout si elle doit être configurée ou exécutée ...

Quelles sont les bibliothèques Python populaires et leurs utilisations? Quelles sont les bibliothèques Python populaires et leurs utilisations? Mar 21, 2025 pm 06:46 PM

L'article traite des bibliothèques Python populaires comme Numpy, Pandas, Matplotlib, Scikit-Learn, Tensorflow, Django, Flask et Demandes, détaillant leurs utilisations dans le calcul scientifique, l'analyse des données, la visualisation, l'apprentissage automatique, le développement Web et H et H

See all articles