Einführung
In diesem Tutorial lernen wir, wie wir das threading-Modul in Python verwenden, um mehrere Ausführungsstränge gleichzeitig auszuführen.
Das threading-Modul in Python bietet eine einfache Möglichkeit, Threads in einem Python-Programm zu erstellen und zu verwalten. Ein Thread ist ein separater Ausführungsfluss innerhalb eines Programms. Indem wir mehrere Threads gleichzeitig ausführen, können wir die Vorteile von Mehrkern-CPUs nutzen und die Leistung unserer Programme verbessern.
Das threading-Modul bietet zwei Klassen zum Erstellen und Verwalten von Threads:
Thread-Klasse: Diese Klasse repräsentiert einen einzelnen Ausführungsstrang.Lock-Klasse: Diese Klasse ermöglicht die Synchronisierung des Zugangs zu gemeinsam genutzten Ressourcen zwischen Threads.
Threads erstellen
Um in Python einen neuen Thread zu erstellen, müssen wir eine neue Instanz der Thread-Klasse erstellen und ihr eine Funktion zum Ausführen übergeben.
Erstellen Sie in der WebIDE ein Projekt namens create_thread.py und geben Sie den folgenden Inhalt ein.
import threading
## Definieren Sie eine Funktion, die im Thread ausgeführt werden soll
def my_function():
print("Hello from thread")
## Erstellen Sie einen neuen Thread
thread = threading.Thread(target=my_function)
## Starten Sie den Thread
thread.start()
## Warten Sie, bis der Thread abgeschlossen ist
thread.join()
## Drucken Sie "Fertig", um anzuzeigen, dass das Programm abgeschlossen ist
print("Done")
In diesem Beispiel wird eine Funktion my_function definiert, die eine Nachricht ausgibt. Anschließend erstellen wir eine neue Instanz der Thread-Klasse und übergeben ihr my_function als Ziel-Funktion. Schließlich starten wir den Thread mit der start-Methode und warten mit der join-Methode, bis er abgeschlossen ist.
Verwenden Sie den folgenden Befehl, um das Skript auszuführen.
python create_thread.py
Synchronisation
Wenn mehrere Threads auf die gleiche gemeinsam genutzte Ressource (z. B. eine Variable oder eine Datei) zugreifen, müssen wir den Zugang zu dieser Ressource synchronisieren, um Wettlaufbedingungen zu vermeiden. Das threading-Modul in Python bietet hierzu eine Lock-Klasse.
Hier ist ein Beispiel für die Verwendung einer Lock, um ein Projekt namens sync.py in der WebIDE zu erstellen und den folgenden Inhalt einzugeben.
import threading
## Erstellen Sie ein Lock, um den Zugang zu der gemeinsam genutzten Ressource zu schützen
lock = threading.Lock()
## Gemeinsame Ressource, die von mehreren Threads geändert werden wird
counter = 0
## Definieren Sie eine Funktion, die jeder Thread ausführen wird
def my_function():
global counter
## Nehmen Sie das Lock vor dem Zugang zur gemeinsam genutzten Ressource
lock.acquire()
try:
## Greifen Sie auf die gemeinsam genutzte Ressource zu
counter += 1
finally:
## Geben Sie das Lock nach der Änderung der gemeinsam genutzten Ressource frei
lock.release()
## Erstellen Sie mehrere Threads, um auf die gemeinsam genutzte Ressource zuzugreifen
threads = []
## Erstellen und starten Sie 10 Threads, die die gleiche Funktion ausführen
for i in range(10):
thread = threading.Thread(target=my_function)
threads.append(thread)
thread.start()
## Warten Sie, bis alle Threads ihre Ausführung abgeschlossen haben
for thread in threads:
thread.join()
## Drucken Sie den Endwert des Zählers
print(counter) ## Ausgabe: 10
Wir erstellen in diesem Beispiel ein Lock-Objekt und eine gemeinsam genutzte Ressource counter. Die my_function-Funktion greift auf die gemeinsam genutzte Ressource zu, indem sie das Lock mit der acquire-Methode nimmt und das Lock mit der release-Methode gibt. Wir erstellen mehrere Threads und starten sie, warten dann mit der join-Methode, bis sie fertig sind. Schließlich drucken wir den Endwert des Zählers.
Verwenden Sie den folgenden Befehl, um das Skript auszuführen.
python sync.py
Thread mit Argumenten
In Python können Sie Argumente an Threads übergeben, indem Sie den args-Parameter verwenden, wenn Sie einen neuen Thread erstellen, oder indem Sie die Thread-Klasse erweitern und Ihren Konstruktor definieren, der Argumente akzeptiert. Hier sind Beispiele für beide Ansätze:
1; Wir erstellen eine Unterklasse der Thread-Klasse und überschreiben die run-Methode, um das Verhalten des Threads zu definieren. Erstellen Sie in der WebIDE ein Projekt namens thread_subclass.py und geben Sie den folgenden Inhalt ein.
import threading
## Definieren Sie eine benutzerdefinierte Thread-Klasse, die die Thread-Klasse erweitert
class MyThread(threading.Thread):
## Überschreiben Sie die run()-Methode, um das Verhalten des Threads zu implementieren
def run(self):
print("Hello from thread")
## Erstellen Sie eine Instanz der benutzerdefinierten Thread-Klasse
thread = MyThread()
## Starten Sie den Thread
thread.start()
## Warten Sie, bis der Thread die Ausführung abgeschlossen hat
thread.join()
Verwenden Sie den folgenden Befehl, um das Skript auszuführen.
python thread_subclass.py
2; Wir erstellen einen Thread und übergeben Argumente an die Ziel-Funktion über den args-Parameter. Erstellen Sie in der WebIDE ein Projekt namens thread_with_args.py und geben Sie den folgenden Inhalt ein
import threading
## Definieren Sie eine Funktion, die ein Parameter akzeptiert
def my_function(name):
print("Hello from", name)
## Erstellen Sie einen neuen Thread mit Ziel-Funktion und Argumenten
thread = threading.Thread(target=my_function, args=("Thread 1",))
## Starten Sie den Thread
thread.start()
## Warten Sie, bis der Thread die Ausführung abgeschlossen hat
thread.join()
Verwenden Sie den folgenden Befehl, um das Skript auszuführen.
python thread_with_args.py
Thread-Pool
In Python können Sie einen Thread-Pool verwenden, um Aufgaben gleichzeitig mit einer vorgegebenen Anzahl von Threads auszuführen. Der Vorteil der Verwendung eines Thread-Pools besteht darin, dass er die Overhead bei der Erstellung und Zerstörung von Threads für jede Aufgabe vermeidet, was die Leistung verbessern kann.
Das concurrent.futures-Modul in Python bietet eine ThreadPoolExecutor-Klasse, die Ihnen ermöglicht, einen Pool von Threads zu erstellen und Aufgaben abzugeben. Hier ist ein Beispiel:
Erstellen Sie in der WebIDE ein Projekt namens thread_pool_range.py und geben Sie den folgenden Inhalt ein.
import concurrent.futures
## Definieren Sie eine Funktion, die in mehreren Threads mit zwei Argumenten ausgeführt werden soll
def my_func(arg1, arg2):
## Definieren Sie hier die Aufgaben, die der Thread ausführt
print(f"Hello from my thread with args {arg1} and {arg2}")
## Erstellen Sie ein ThreadPoolExecutor-Objekt mit maximal 5 Arbeitsthreads
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
## Übermitteln Sie jede Aufgabe (Funktionsaufruf mit seinen Argumenten) an den Ausführenden, um in einem separaten Thread verarbeitet zu werden
## Die submit()-Methode gibt ein Future-Objekt zurück, das das Ergebnis der asynchronen Berechnung darstellt
for i in range(10):
executor.submit(my_func, i, i+1)
In diesem Beispiel definieren wir eine Funktion my_func, die zwei Argumente nimmt. Wir erstellen einen ThreadPoolExecutor mit maximal 5 Arbeitsthreads. Anschließend durchlaufen wir eine Zahlenreihe und übermitteln Aufgaben an den Thread-Pool mit der executor.submit()-Methode. Jede übermittelte Aufgabe wird auf einem der verfügbaren Arbeitsthreads ausgeführt.
Tipps: Das
ThreadPoolExecutor-Objekt wird als Kontext-Manager verwendet. Dadurch wird sichergestellt, dass alle Threads richtig aufgeräumt werden, wenn der Code innerhalb des with-Blocks abgeschlossen ist.
Verwenden Sie den folgenden Befehl, um das Skript auszuführen.
python thread_pool_range.py
Die submit()-Methode gibt sofort ein Future-Objekt zurück, das das Ergebnis der übermittelten Aufgabe darstellt. Sie können die result()-Methode des Future-Objekts verwenden, um den Rückgabewert der Aufgabe abzurufen. Wenn die Aufgabe eine Ausnahme auslöst, wird beim Aufruf von result() diese Ausnahme ausgelöst.
Sie können auch die map()-Methode der ThreadPoolExecutor-Klasse verwenden, um die gleiche Funktion auf eine Sammlung von Elementen anzuwenden. Beispielsweise erstellen Sie in der WebIDE ein Projekt namens thread_pool_map.py und geben Sie den folgenden Inhalt ein.:
import concurrent.futures
## Definieren Sie eine Funktion, die in mehreren Threads ausgeführt werden soll
def my_func(item):
## Definieren Sie hier die Aufgaben, die der Thread ausführt
print(f"Hello from my thread with arg {item}")
## Erstellen Sie eine Liste von Elementen, die von den Threads verarbeitet werden sollen
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
## Erstellen Sie ein ThreadPoolExecutor-Objekt mit maximal 5 Arbeitsthreads
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
## Übermitteln Sie jedes Element an den Ausführenden, um in einem separaten Thread verarbeitet zu werden
## Die map()-Methode gibt automatisch die Ergebnisse in der Reihenfolge zurück
executor.map(my_func, items)
In diesem Beispiel definieren wir eine Funktion my_func, die ein Argument nimmt. Wir erstellen eine Liste von Elementen und übermitteln sie an den Thread-Pool mit der executor.map()-Methode. Jedes Element in der Liste wird als Argument an my_func übergeben, und jedes Element wird auf einem der verfügbaren Arbeitsthreads ausgeführt.
Verwenden Sie den folgenden Befehl, um das Skript auszuführen.
python thread_pool_map.py
Die Ergebnisse, die aus thread_pool_range.py und thread_pool_map.py erhalten werden, sind die gleichen.
Dämon-Threads
In Python ist ein Daemon-Thread ein Thread-Typ, der im Hintergrund läuft und das Beenden des Programms nicht verhindert. Wenn alle nicht-Daemon-Threads abgeschlossen sind, beendet sich der Python-Interpreter, unabhängig davon, ob noch einige Daemon-Threads laufen.
Erstellen Sie in der WebIDE ein Projekt namens daemon_thread_with_args.py und geben Sie den folgenden Inhalt ein.
import threading
import time
## Definieren Sie eine Funktion, die endlos läuft und regelmäßig Nachrichten ausgibt
def my_function():
while True:
print("Hello from thread")
time.sleep(1)
## Erstellen Sie einen Daemon-Thread, der die Ziel-Funktion ausführt
thread = threading.Thread(target=my_function, daemon=True)
## Starten Sie den Thread
thread.start()
## Das Hauptprogramm setzt die Ausführung fort und gibt eine Nachricht aus
print("Main program")
## Warten Sie einige Sekunden, bevor das Programm beendet wird
time.sleep(5)
## Das Programm beendet sich, und der Daemon-Thread wird automatisch beendet
print("Main thread exiting...")
In diesem Beispiel erstellen wir einen Thread, der eine Endlosschleife ausführt und jede Sekunde eine Nachricht ausgibt, indem die time.sleep()-Funktion verwendet wird. Wir markieren den Thread als Daemon mit dem daemon-Parameter, um ihn automatisch zu beenden, wenn das Hauptprogramm beendet wird. Das Hauptprogramm setzt weiterhin zu laufen und gibt eine Nachricht aus. Wir warten einige Sekunden, und das Programm beendet sich, wobei der Daemon-Thread ebenfalls beendet wird.
Verwenden Sie dann den folgenden Befehl, um das Skript auszuführen.
python daemon_thread_with_args.py
Natürlich können wir auch einen Thread als Daemon setzen, indem wir die setDaemon(True)-Methode auf der Thread-Instanz aufrufen. Beispielsweise erstellen Sie in der WebIDE ein Projekt namens daemon_thread_with_func.py und geben Sie den folgenden Inhalt ein:
import threading
import time
## Definieren Sie eine Funktion, die endlos läuft und regelmäßig Nachrichten ausgibt
def my_function():
while True:
print("Hello from thread")
time.sleep(1)
## Erstellen Sie einen neuen Thread mit Ziel-Funktion
thread = threading.Thread(target=my_function)
## Setzen Sie das Daemon-Flag auf True, damit der Thread im Hintergrund läuft und beim Beenden des Hauptprogramms beendet wird
thread.setDaemon(True)
## Starten Sie den Thread
thread.start()
## Das Hauptprogramm setzt die Ausführung fort und gibt eine Nachricht aus
print("Main program")
## Warten Sie einige Sekunden, bevor das Programm beendet wird
time.sleep(5)
## Das Programm beendet sich und der Daemon-Thread wird automatisch beendet
print("Main thread exiting...")
Das Ausführen des Skripts mit dem folgenden Befehl liefert das gleiche Ergebnis wie das obige Beispiel.
python daemon_thread_with_func.py
Event-Objekt
In Python können Sie das threading.Event-Objekt verwenden, um Threads zu ermöglichen, bis ein bestimmtes Ereignis eintritt, bevor sie fortfahren. Das Event-Objekt bietet eine Möglichkeit, dass ein Thread signalisiert, dass ein Ereignis aufgetreten ist, und andere Threads können auf dieses Signal warten.
Erstellen Sie in der WebIDE ein Projekt namens event_object.py und geben Sie den folgenden Inhalt ein.
import threading
## Erstellen Sie ein Event-Objekt
event = threading.Event()
## Definieren Sie eine Funktion, die auf das Setzen des Events wartet
def my_function():
print("Waiting for event")
## Warten Sie auf das Setzen des Events
event.wait()
print("Event received")
## Erstellen Sie einen neuen Thread mit Ziel-Funktion
thread = threading.Thread(target=my_function)
## Starten Sie den Thread
thread.start()
## Signalieren Sie das Event nach einigen Sekunden
## Der wait()-Aufruf in der Ziel-Funktion wird jetzt zurückgeben und die Ausführung fortsetzen
event.set()
## Warten Sie, bis der Thread die Ausführung abgeschlossen hat
thread.join()
In diesem Beispiel erstellen wir ein Event-Objekt mit der Event-Klasse. Wir definieren eine Funktion, die auf das Signal des Events mit der wait-Methode wartet und dann eine Nachricht ausgibt. Wir erstellen einen neuen Thread und starten ihn. Nach einigen Sekunden signalieren wir das Event mit der set-Methode. Der Thread erhält das Event und gibt eine Nachricht aus. Schließlich warten wir mit der join-Methode, bis der Thread fertig ist.
Verwenden Sie dann den folgenden Befehl, um das Skript auszuführen.
python event_object.py
Timer-Objekt
In Python können Sie das threading.Timer-Objekt verwenden, um eine Funktion so zu planen, dass sie nach Ablauf einer bestimmten Zeit ausgeführt wird. Das Timer-Objekt erstellt einen neuen Thread, der bis zum Ablauf des angegebenen Zeitintervalls wartet, bevor er die Funktion ausführt.
Erstellen Sie in der WebIDE ein Projekt namens timer_object.py und geben Sie den folgenden Inhalt ein.
import threading
## Definieren Sie eine Funktion, die vom Timer nach 5 Sekunden ausgeführt wird
def my_function():
print("Hello from timer")
## Erstellen Sie einen Timer, der die Ziel-Funktion nach 5 Sekunden ausführt
timer = threading.Timer(5, my_function)
## Starten Sie den Timer
timer.start()
## Warten Sie, bis der Timer abgeschlossen ist
timer.join()
In diesem Beispiel erstellen wir ein Timer-Objekt mit der Timer-Klasse und übergeben ihm eine Zeitverzögerung in Sekunden und eine auszuführende Funktion. Wir starten den Timer mit der start-Methode und warten mit der join-Methode, bis er abgeschlossen ist. Nach 5 Sekunden wird die Funktion ausgeführt und eine Nachricht ausgegeben.
Verwenden Sie dann den folgenden Befehl, um das Skript auszuführen.
python timer_object.py
Tipps: Der Timer-Thread läuft separat, sodass er möglicherweise nicht mit dem Hauptthread synchronisiert ist. Wenn Ihre Funktion auf einem gemeinsamen Zustand oder Ressourcen zugreift, müssen Sie die Zugangssynchronisierung entsprechend vornehmen. Denken Sie auch daran, dass der Timer-Thread das Beenden des Programms nicht verhindert, wenn er noch läuft, wenn alle anderen nicht-Daemon-Threads abgeschlossen sind.
Barriere-Objekt
In Python können Sie das threading.Barrier-Objekt verwenden, um mehrere Threads an vordefinierten Synchronisierungspunkten zu synchronisieren. Das Barriere-Objekt bietet eine Möglichkeit, dass eine Gruppe von Threads aufeinander warten, bis sie einen bestimmten Punkt in ihrer Ausführung erreicht haben, bevor sie fortfahren.
Erstellen Sie in der WebIDE ein Projekt namens barrier_object.py und geben Sie den folgenden Inhalt ein.
import threading
## Erstellen Sie ein Barriere-Objekt für 3 Threads
barrier = threading.Barrier(3)
## Definieren Sie eine Funktion, die an der Barriere wartet
def my_function():
print("Before barrier")
## Warten Sie, bis alle drei Threads die Barriere erreicht haben
barrier.wait()
print("After barrier")
## Erstellen Sie 3 Threads mithilfe einer Schleife und starten Sie sie
threads = []
for i in range(3):
thread = threading.Thread(target=my_function)
threads.append(thread)
thread.start()
## Warten Sie, bis alle Threads die Ausführung abgeschlossen haben
for thread in threads:
thread.join()
In diesem Beispiel erstellen wir ein Barrier-Objekt mit der Barrier-Klasse und übergeben ihm die Anzahl der Threads, auf die gewartet werden soll. Mit der wait-Methode definieren wir eine Funktion, die auf die Barriere wartet und eine Nachricht ausgibt. Wir erstellen drei Threads und starten sie. Jeder Thread wartet auf die Barriere, sodass alle Threads bis alle von ihnen die Barriere erreicht haben, warten werden. Schließlich warten wir mit der join-Methode, bis alle Threads fertig sind.
Verwenden Sie dann den folgenden Befehl, um das Skript auszuführen.
python barrier_object.py
Zusammenfassung
Das war's! Sie wissen jetzt, wie Sie das Python-threading-Modul in Ihrem Code verwenden. Es kann uns helfen, die Grundprinzipien und Techniken der parallelen Programmierung gründlicher zu verstehen, sodass wir effizientere parallele Anwendungen besser entwickeln können.



