Il y a un modèle que le programme ne s'est pas arrêté lors de l'utilisation du thread Python

Programme "Je ne peux pas m'arrêter ..." Je "Veuillez arrêter"

Cet article est l'article du 7ème jour du N High School Advent Calendar 2019. Je suis actuellement en deuxième année de ma deuxième année (il y avait beaucoup de choses lors de mon transfert) et je suis en cours scolaire. Je suis très reconnaissant que N High School puisse réaliser son propre projet pendant le temps de programmation tant qu'il termine les tâches essentielles.

Dans cet article, j'écrirai sur les problèmes que j'ai rencontrés lors de la création de bots Discord et Twitter en Python. Veuillez signaler toute erreur.

Aperçu

Lorsque j'ai essayé d'arrêter un programme utilisant le threading Python avec Keyboard Interrupt (Ctrl + C), cela ne s'est pas arrêté immédiatement pour une raison quelconque. Après une enquête plus approfondie, sys.exit () ne s'est pas arrêté.

environnement

OS: Windows 10 Home Runtime: Python 3.8.0

Entraine toi

Pour le moment, j'ai décidé d'écrire du code en utilisant le threading pour la vérification.

import threading
import time

#Définition des fonctions
def a():
    for i in range(5):
        time.sleep(1)
        print("A" + str(i))

def b():
    time.sleep(0.5)
    for j in range(5):
        time.sleep(1)
        print("B" + str(j))

#Création d'objets de thread
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Courir
t1.start()
t2.start()

#Attends la fin
t1.join()
t2.join()

print("Finish")

Comme prévu, la sortie ressemble à ceci: Fin était affiché en même temps que B4 était affiché.

A0
B0
A1
B1
A2
B2
A3
B3
A4
B4
Finish

Maintenant, remodelons cela en une boucle infinie.

import threading
import time

#Définition des fonctions
def a():
    c=1
    while True:
        time.sleep(1)
        print("A" + str(c))
        c+=1

def b():
    k=1
    time.sleep(0.5)
    while True:
        time.sleep(1)
        print("B" + str(k))
        k+=1

#Création d'objets de thread
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Courir
t1.start()
t2.start()

#Attends la fin
t1.join()
t2.join()

La sortie est la suivante.

A1
B1
A2
B2
A3
B3
^CTraceback (most recent call last):
  File "***********.py", line 28, in <module>
    t1.join()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1011, in join
    self._wait_for_tstate_lock()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock
    elif lock.acquire(block, timeout):
KeyboardInterrupt
A4
B4
A5
B5
A6
B6
^CException ignored in: <module 'threading' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py'>
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1388, in _shutdown
    lock.acquire()
KeyboardInterrupt: 

Pour une raison quelconque, il ne s'est pas arrêté à la première interruption du clavier. Cette fois, je l'ai fait deux fois et ça s'est arrêté, mais je veux l'éviter si possible.

Solution?

Vous n'avez pas à "attendre la fin". En d'autres termes, supprimez simplement «**. Join ()». Quand je supprime t1.join () et t2.join () et que je l'exécute, cela devient comme ça.

A1
B1
A2
B2
^CException ignored in: <module 'threading' from '/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py'>
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/threading.py", line 1388, in _shutdown
    lock.acquire()
KeyboardInterrupt:

Il fut un temps où je pensais: "Si c'est un processus qui utilise While True, il ne se terminera pas au milieu, et si vous vous arrêtez avec Ctrl + C, oui." Mais il y a des scènes surprenantes que je veux arrêter. Par exemple, lorsque vous souhaitez arrêter le bot avec une commande. Le contenu suivant a été découvert à ce moment-là.

sys.exit () ne fonctionne pas non plus

import threading
import time
import sys

#Définition des fonctions
def a():
    c=1
    while True:
        time.sleep(1)
        print("A" + str(c))
        c+=1

def b():
    k=1
    time.sleep(0.5)
    while True:
        time.sleep(1)
        print("B" + str(k))
        k+=1

#Création d'objets de thread
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Courir
t1.start()
t2.start()

#résiliation forcée
print("Terminate")
sys.exit()
print("Terminated")

La sortie attendue est une ligne «Terminer». C'est parce que le programme ne doit pas être exécuté après sys.exit () (c'est strictement faux, comme décrit plus loin). Cependant, lorsque celui-ci est réellement utilisé, la sortie suivante est obtenue.

Terminate
A1
B1
A2
B2
A3
B3
A4
B4

sys.exit () s'exécute après que Terminate et Terminated soit masqué, mais les deux fonctions ci-dessus ont été exécutées normalement.

Cause

Il y a eu une erreur lors de la reconnaissance de sys.exit (). Cela n'arrête pas tout le programme, cela arrête le fil. Le thread qui s'arrête dans le programme ci-dessus est seulement le thread qui exécute print (" Terminate "), et sys.exit () n'est pas arrivé aux deux threads qui bouclent indéfiniment. Une façon de l'arrêter est d'exécuter sys.exit () dans l'objet thread. Mais ce que je veux faire, c'est "arrêter tous les threads à la fois".

Solution

Faites des threads autres que le thread principal un démon.

import threading
import time
import sys

#Définition des fonctions
def a():
    c=1
    while True:
        time.sleep(1)
        print("A" + str(c))
        c+=1

def b():
    k=1
    time.sleep(0.5)
    while True:
        time.sleep(1)
        print("B" + str(k))
        k+=1

def c():
    while True:
        n = input()
        if n == "e":
            print("Terminate")
            sys.exit()

#Création d'objets de thread
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Diabolisation
t1.setDaemon(True)
t2.setDaemon(True)

#Courir
t1.start()
t2.start()
c() # c()Exécuter uniquement sur le thread principal

Changé pour exécuter sys.exit () lors de la réception de l'entrée ʻe`. Le résultat de sortie est le suivant.

A1
B1
A2
e
Terminate

Si vous appuyez sur e et appuyez sur Entrée (Retour), l'exécution s'arrêtera là. Le thread démon se comporte comme ** disparaît automatiquement lorsqu'un thread autre que le thread démon n'est pas en cours d'exécution **. S'il n'y a qu'un seul processus qui inclut sys.exit (), il peut être préférable de l'exécuter sur le thread principal, c'est-à-dire sur le côté le plus extérieur sans faire threading.Thread ().

Résumé

Pour être honnête, j'ai essayé de découvrir la cause, mais je ne sais pas. D'une manière ou d'une autre, le signal était quelque chose comme ça, mais je ne peux pas l'écrire correctement avec mes propres compétences, donc je ne le posterai pas. Au cours de la rédaction de cet article, j'ai beaucoup recherché sur le threading, mais il semble qu'il existe encore diverses fonctions, et il peut y avoir des moyens de réaliser ce que je veux faire en dehors de celles énumérées ci-dessus. Cependant, si j'essaye de le faire dans le cadre de ma compréhension, ce sera comme ci-dessus. Si cela reste bloqué, je vais essayer de trouver un autre moyen.

Recommended Posts

Il y a un modèle que le programme ne s'est pas arrêté lors de l'utilisation du thread Python
[Ev3dev] Créez un programme qui capture LCD (écran) en utilisant python
Un programme qui utilise Python pour lire des fichiers indésirables
[Python] Un programme qui arrondit le score
Solution de contournement pour sys.argv non transmise lors de l'exécution d'un script Python avec uniquement le nom de fichier sur Python2.7 sous Windows
Notez que GoogleMap.getProjection dans l'API Google Maps Android n'est pas un singleton
Il y a un modèle que le programme ne s'est pas arrêté lors de l'utilisation du thread Python
[Python] Un programme qui trouve les valeurs minimales et maximales sans utiliser de méthodes
[Python] Un programme qui compte le nombre de vallées
[Python] Un programme qui compare les positions des kangourous.
Une histoire qui était pratique lorsque j'ai essayé d'utiliser le module d'adresse IP python
Utilisez Ruby et Python pour trouver la probabilité qu'une carte avec un nombre naturel de 1 à 100 soit un multiple de 3 et non un multiple de 5.
La liste Python n'est pas une liste
Y a-t-il un biais dans les nombres qui apparaissent dans les nombres de Fibonacci?
[Python] Un programme qui trouve les types d'oiseaux les plus courants
L'histoire selon laquelle pyenv n'a pas passé la commande d'exécution python PATH
Lors de l'écriture dans un fichier csv avec python, une histoire que j'ai fait une légère erreur et n'a pas respecté la date de livraison
Lors de l'incrémentation de la valeur d'une clé qui n'existe pas
Python échouera s'il y a un espace après la barre oblique inverse
Jouez des sons en Python en supposant que le clavier est un clavier de piano
J'ai un TypeError: l'objet 'int' n'est pas itérable lors de l'utilisation de keras
Solution de contournement pour sys.argv non transmise lors de l'exécution d'un script Python avec uniquement le nom de fichier sur Python2.7 sous Windows
L'histoire de l'erreur de hachage est apparue lors de l'utilisation de Pipenv
[Python] Apparaît lors de l'utilisation de iterdir () etc. [Errno 20] Pas un répertoire: '*** / .DS_Store'
Un programme qui détermine si un nombre entré en Python est un nombre premier
[Python] J'ai essayé de créer un programme simple qui fonctionne sur la ligne de commande en utilisant argparse
L'histoire selon laquelle le remplacement de la liste bidimensionnelle n'a pas fonctionné en python
Construire un environnement Python sur Ubuntu (lorsque pip n'était pas la valeur par défaut)
Lors de l'écriture d'un programme en Python
[Python] Un programme qui fait pivoter le contenu de la liste vers la gauche
Un programme qui détermine automatiquement s'il s'agit d'une animation ou d'une photo lorsque vous entrez l'image d'une personne [python]
[Python] Un programme qui calcule le nombre de segments de chocolat qui remplissent les conditions
Vérifier les points lorsque MIDI ne fonctionne pas dans un programme utilisant SDL_mixer
[Python] Un programme qui calcule le nombre de chaussettes jumelées
Notez que GoogleMap.getProjection dans l'API Google Maps Android n'est pas un singleton
Notifier à l'aide du Centre de notifications lorsque l'environnement d'exécution est macOS en Python
Une note utile lors de l'utilisation de Python après une longue période
Bug où "val_loss" n'est pas trouvé lors de l'utilisation de l'arrêt anticipé dans pytorch-lightning (0.5.3.2)
python Remarque: lorsque easy_install ne peut pas être utilisé
[Python] Un programme qui crée des escaliers avec #
Il semble que la version de pyflakes ne soit pas la dernière lorsque flake8 est installé
Transformez un programme Python en démon et exécutez-le automatiquement au démarrage du système d'exploitation
Sont Php / Ruby / Python qui ne s'exécute que lorsque le fichier est appelé directement
Une histoire qui ne s'est pas terminée par la sortie lors du tournage avec l'entrée de tuyau
Installez séparément une version de Python qui n'est pas préinstallée sur votre Mac
[Python] Solution au problème que les éléments sont liés lors de la copie d'une liste
[Python] Un programme qui calcule la différence entre les valeurs totales diagonales
Y a-t-il une contradiction entre le parti qui protège le peuple de la NHK et le parti qui protège la NHK du peuple?
Un programme qui supprime les instructions en double en Python
Programme pour rechercher la même image
Un programme shell qui affiche une séquence de Fibonacci
C'est une histoire de ferroutage sur le service qui renvoie "Nyan" lorsque vous appuyez sur ping
Comment utiliser pip, un système de gestion de paquets indispensable pour utiliser Python
Une note sur l'implémentation de la bibliothèque qui explore les hyperparamètres à l'aide de l'optimisation bayésienne en Python
[Python] Un programme qui trouve le nombre d'étapes le plus court dans un jeu qui traverse les nuages
Pour moi qui étais confus parce que sudo python ne fonctionnait pas lors de l'utilisation de virtualenv
Programme qui résume les données csv de l’historique des transactions de l’action SBI Securities [Python3]
Une commande pour vérifier si quelque chose ne va pas lorsque le serveur ne fait rien