Es gibt ein Muster, das das Programm bei Verwendung von Python-Threading nicht gestoppt hat

Programm "Ich kann nicht aufhören ..." Ich "Bitte hör auf"

Dieser Artikel ist der Artikel zum 7. Tag des N High School Adventskalenders 2019. Ich bin derzeit im zweiten Jahr meines zweiten Jahres (es gab viele Dinge, als ich wechselte) und besuche einen Schulkurs. Ich bin sehr dankbar, dass die N High School sein eigenes Projekt in der Programmierzeit durchführen kann, solange er die wesentlichen Aufgaben erledigt.

In diesem Artikel werde ich über die Probleme schreiben, mit denen ich beim Erstellen von Discord- und Twitter-Bots in Python konfrontiert war. Bitte weisen Sie auf Fehler hin.

Überblick

Als ich versuchte, ein Programm mit Python-Threading mit Tastaturunterbrechung (Strg + C) zu stoppen, wurde es aus irgendeinem Grund nicht sofort gestoppt. Bei weiteren Untersuchungen hörte sys.exit () nicht auf.

Umgebung

OS: Windows 10 Home Runtime: Python 3.8.0

Trainieren

Vorerst habe ich beschlossen, Code zur Überprüfung mithilfe von Threading zu schreiben.

import threading
import time

#Funktionsdefinition
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))

#Thread-Objekterstellung
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Lauf
t1.start()
t2.start()

#Warten Sie bis zum Ende
t1.join()
t2.join()

print("Finish")

Wie erwartet sieht die Ausgabe folgendermaßen aus: Fertig stellen wurde gleichzeitig mit B4 angezeigt.

A0
B0
A1
B1
A2
B2
A3
B3
A4
B4
Finish

Lassen Sie uns dies nun in eine Endlosschleife umwandeln.

import threading
import time

#Funktionsdefinition
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

#Thread-Objekterstellung
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Lauf
t1.start()
t2.start()

#Warten Sie bis zum Ende
t1.join()
t2.join()

Die Ausgabe ist wie folgt.

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: 

Aus irgendeinem Grund hörte es beim ersten Keyboard Interrupt nicht auf. Diesmal habe ich es zweimal gemacht und es hat aufgehört, aber ich möchte es nach Möglichkeit vermeiden.

Lösung?

Sie müssen nicht "bis zum Ende warten". Mit anderen Worten, löschen Sie einfach **. Join (). Wenn ich tatsächlich "t1.join ()" und "t2.join ()" lösche und ausführe, wird es so.

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:

Es gab eine Zeit, in der ich dachte: "Wenn es sich um einen Prozess handelt, der While True verwendet, endet er nicht in der Mitte, und wenn Sie mit Strg + C aufhören, ja." Aber es gibt überraschende Szenen, die ich stoppen möchte. Zum Beispiel, wenn Sie den Bot mit einem Befehl herunterfahren möchten. Die folgenden Inhalte wurden zu diesem Zeitpunkt entdeckt.

sys.exit () funktioniert auch nicht

import threading
import time
import sys

#Funktionsdefinition
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

#Thread-Objekterstellung
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Lauf
t1.start()
t2.start()

#erzwungene Kündigung
print("Terminate")
sys.exit()
print("Terminated")

Die erwartete Ausgabe ist eine "Terminate" -Zeile. Dies liegt daran, dass das Programm nicht nach "sys.exit ()" ausgeführt werden sollte (dies ist streng falsch, wie später beschrieben). Wenn dies jedoch tatsächlich betrieben wird, wird die folgende Ausgabe erhalten.

Terminate
A1
B1
A2
B2
A3
B3
A4
B4

sys.exit () wird ausgeführt, nachdem Terminate und Terminated ausgeblendet sind, aber die beiden oben genannten Funktionen wurden normal ausgeführt.

Ursache

Beim Erkennen von "sys.exit ()" ist ein Fehler aufgetreten. Es stoppt nicht das gesamte Programm, es stoppt den Thread. Der einzige Thread, der im obigen Programm stoppt, ist der Thread, der "print (" Terminate ")" ausführt, und "sys.exit ()" ist nicht bei den beiden Threads angekommen, die sich unendlich wiederholen. Eine Möglichkeit, dies zu stoppen, besteht darin, sys.exit () innerhalb des Thread-Objekts auszuführen. Aber was ich tun möchte, ist "alle Threads auf einmal stoppen".

Lösung

Dämonisieren Sie andere Threads als den Haupt-Thread.

import threading
import time
import sys

#Funktionsdefinition
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()

#Thread-Objekterstellung
t1 = threading.Thread(target=a)
t2 = threading.Thread(target=b)

#Dämonisierung
t1.setDaemon(True)
t2.setDaemon(True)

#Lauf
t1.start()
t2.start()
c() # c()Nur auf dem Haupt-Thread ausführen

Beim Empfang der Eingabe "e" wurde geändert, um "sys.exit ()" auszuführen. Das Ausgabeergebnis ist wie folgt.

A1
B1
A2
e
Terminate

Wenn Sie e und Enter (Return) drücken, wird die Ausführung dort gestoppt. Der Daemon-Thread verhält sich so, dass ** automatisch verschwindet, wenn ein anderer Thread als der Daemon-Thread nicht ausgeführt wird **. Wenn es nur einen Prozess gibt, der "sys.exit ()" enthält, ist es möglicherweise besser, ihn auf dem Hauptthread auszuführen, dh auf der äußersten Seite, ohne "threading.Thread ()" auszuführen.

Zusammenfassung

Um ehrlich zu sein, habe ich versucht, die Ursache herauszufinden, aber ich weiß es nicht. Irgendwie war das Signal so ähnlich, aber ich kann es mit meinen eigenen Fähigkeiten nicht richtig schreiben, also werde ich es nicht posten. Während ich diesen Artikel schrieb, habe ich viel über das Threading recherchiert, aber es scheint, dass es immer noch verschiedene Funktionen gibt und es möglicherweise Möglichkeiten gibt, zu realisieren, was ich tun möchte, außer den oben aufgeführten. Wenn ich jedoch versuche, dies im Rahmen meines Verständnisses zu tun, wird es wie oben sein. Wenn dies stecken bleibt, werde ich versuchen, einen anderen Weg zu finden.

Recommended Posts

Es gibt ein Muster, das das Programm bei Verwendung von Python-Threading nicht gestoppt hat
[Ev3dev] Erstellen Sie ein Programm, das das LCD (Bildschirm) mit Python erfasst
Ein Programm, das Python zum Abspielen von Junk verwendet
[Python] Ein Programm, das die Partitur rundet
Problemumgehung für sys.argv wird nicht übergeben, wenn ein Python-Skript mit nur dem Dateinamen unter Python2.7 unter Windows ausgeführt wird
Beachten Sie, dass GoogleMap.getProjection in der Android-API von Google Maps kein Singleton ist
Es gibt ein Muster, das das Programm bei Verwendung von Python-Threading nicht gestoppt hat
[Python] Ein Programm, das die minimalen und maximalen Werte ohne Verwendung von Methoden findet
[Python] Ein Programm, das die Anzahl der Täler zählt
[Python] Ein Programm, das die Positionen von Kängurus vergleicht.
Eine Geschichte, die praktisch war, als ich versuchte, das Python-IP-Adressmodul zu verwenden
Verwenden Sie Ruby und Python, um die Wahrscheinlichkeit zu ermitteln, dass eine Karte mit einer natürlichen Zahl von 1 bis 100 ein Vielfaches von 3 und kein Vielfaches von 5 ist.
Gibt es eine Verzerrung in den Zahlen, die in den Fibonacci-Zahlen erscheinen?
[Python] Ein Programm, das die häufigsten Vogeltypen findet
Die Geschichte, dass pyenv den Python-Ausführungsbefehl PATH nicht bestanden hat
Beim Schreiben in eine CSV-Datei mit Python habe ich einen kleinen Fehler gemacht und den Liefertermin nicht eingehalten
Beim Inkrementieren des Werts eines Schlüssels, der nicht vorhanden ist
Python schlägt fehl, wenn nach dem Backslash ein Leerzeichen steht
Spielen Sie Sounds in Python ab, vorausgesetzt, die Tastatur ist eine Klaviertastatur
Ich habe einen TypeError: 'int'-Objekt ist bei Verwendung von Keras nicht iterierbar
Problemumgehung für sys.argv wird nicht übergeben, wenn ein Python-Skript mit nur dem Dateinamen unter Python2.7 unter Windows ausgeführt wird
Die Geschichte, dass ein Hash-Fehler bei der Verwendung von Pipenv auftrat
[Python] Erscheint bei Verwendung von iterdir () usw. [Errno 20] Kein Verzeichnis: '*** / .DS_Store'
Ein Programm, das bestimmt, ob eine in Python eingegebene Zahl eine Primzahl ist
[Python] Ich habe versucht, mit argparse ein einfaches Programm zu erstellen, das in der Befehlszeile funktioniert
Die Geschichte, dass das Ersetzen der zweidimensionalen Liste in Python nicht funktioniert hat
Erstellen einer Python-Umgebung unter Ubuntu (wenn pip nicht die Standardeinstellung war)
Beim Schreiben eines Programms in Python
[Python] Ein Programm, das den Inhalt der Liste nach links dreht
Ein Programm, das automatisch feststellt, ob es sich um eine Animation oder ein Foto handelt, wenn Sie das Bild einer Person eingeben [Python]
[Python] Ein Programm, das die Anzahl der Schokoladensegmente berechnet, die die Bedingungen erfüllen
Überprüfen Sie Punkte, wenn MIDI in einem Programm mit SDL_mixer nicht funktioniert
[Python] Ein Programm, das die Anzahl der gepaarten Socken berechnet
Beachten Sie, dass GoogleMap.getProjection in der Android-API von Google Maps kein Singleton ist
Benachrichtigen Sie mit Notification Center, wenn die Ausführungsumgebung in Python macOS ist
Ein nützlicher Hinweis, wenn Sie Python nach langer Zeit verwenden
Fehler, bei dem 'val_loss' bei Verwendung von Early Stopping in Pytorch-Lightning (0.5.3.2) nicht gefunden wird.
Python Hinweis: Wenn easy_install nicht verwendet werden kann
[Python] Ein Programm, das Treppen mit # erstellt
Es scheint, dass die Version von Pyflakes nicht die neueste ist, wenn flake8 installiert ist
Machen Sie aus einem Python-Programm einen Daemon und führen Sie es automatisch aus, wenn das Betriebssystem gestartet wird
Sind Php / Ruby / Python, die nur ausgeführt werden, wenn die Datei direkt aufgerufen wird
Eine Geschichte, die beim Drehen mit Rohreingabe nicht mit dem Verlassen endete
Installieren Sie separat eine Version von Python, die nicht auf Ihrem Mac vorinstalliert ist
[Python] Lösung für das Problem, dass Elemente beim Kopieren einer Liste verknüpft werden
[Python] Ein Programm, das die Differenz zwischen diagonalen Gesamtwerten berechnet
Gibt es einen Widerspruch zwischen der Partei, die die Menschen vor NHK schützt, und der Partei, die NHK vor den Menschen schützt?
Ein Programm, das doppelte Anweisungen in Python entfernt
Programm zur Suche nach demselben Bild
Ein Shell-Programm, das eine Fibonacci-Sequenz anzeigt
Es ist eine Huckepack-Geschichte über den Dienst, der "Nyan" zurückgibt, wenn Sie Ping drücken
Verwendung von pip, einem Paketverwaltungssystem, das für die Verwendung von Python unverzichtbar ist
Ein Hinweis zur Bibliotheksimplementierung, in der Hyperparameter mithilfe der Bayes'schen Optimierung in Python untersucht werden
[Python] Ein Programm, das die kürzeste Anzahl von Schritten in einem Spiel findet, das Wolken überquert
Für mich, der verwirrt war, weil Sudo Python bei der Verwendung von virtualenv nicht funktionierte
Programm, das die CSV-Daten der Transaktionshistorie der SBI Securities-Aktie zusammenfasst [Python3]
Ein Befehl zum Überprüfen, wenn etwas schief geht, wenn der Server nichts tut