Threading ermöglicht es, verschiedene Teile eines Prozesses gleichzeitig auszuführen (Quelle: RealPython). Diese Teile sind in der Regel eigenständig und haben eine eigene Ausführungseinheit, gehören aber zum selben Prozess. Ein Prozess ist einfach ein laufendes Programm mit einzelnen Einheiten, die parallel laufen können. Beispiele: Ein Webbrowser ist ein Prozess, eine Anwendung, die mehrere Kameras gleichzeitig betreibt, ist ein Prozess; auch ein Videospiel ist ein Prozess.
Innerhalb eines Prozesses gibt es das Konzept des Multithreadings, bei dem mehrere Threads gemeinsam ein Ziel verfolgen. Der größte Vorteil von Threads ist, dass du Programmteile parallel laufen lassen kannst.
Verstehen wir Threading anhand eines Beispiels: Stell dir eine Anwendung vor, die die Anzahl der Autos zählt, die in das Parkhaus eines Einkaufszentrums ein- und ausfahren. Dein Aufbau umfasst mehrere Kameras, die Ein- und Ausfahrten überwachen und mit einem zentralen Gerät verbunden sind. Jede Kamera hat einen Algorithmus zur Überwachung des Verkehrsflusses, der zum selben Prozess gehört. Jede Kamera samt Algorithmus kann jedoch in einem eigenen Thread laufen. Sogar das Auslesen der Kameraframes und die Inferenz des Algorithmus auf diesen Frames können zwei getrennte Threads sein.
Ein weiteres Beispiel ist ein Videospiel, bei dem der Prozess Aufgaben parallel ausführen muss – etwa Grafik, Nutzerinteraktion und Netzwerkkommunikation (bei Multiplayer) – damit es jederzeit reaktionsschnell bleibt. Dafür nutzt man Multithreading, wobei jeder Thread eine unabhängige Aufgabe übernimmt.
Ein Thread hat seinen eigenen Ausführungsfluss, das heißt, im Prozess passieren mehrere Dinge gleichzeitig.
Wichtig: Jeder Prozess hat mindestens einen Thread, den main thread. Selbst wenn du keine zusätzlichen Threads definierst, existiert der Main-Thread – also der Prozess selbst.
Im obigen Diagramm siehst du einen Prozess mit dem Main-Thread (mit globalen Variablen) und drei Threads t1, t2 und t3. Jeder Thread hat eigene lokale Variablen und einen eigenen Ausführungsfluss. Die Threads teilen sich in der Regel die Ressourcen des Prozesses: Was dem Main-Thread zur Verfügung steht, wird auch mit t1, t2 und t3 geteilt. Alle Threads haben Zugriff auf globale Variablen und zusätzlich ihre lokalen.
Es gibt verschiedene Arten von Threads:
Kernel-Thread
User-Thread
Kombination aus Kernel- und User-Thread
Schauen wir uns nun einige Vorteile von Threading in deinem Programm an:
Mit Multithreading kann ein Programm schneller ausführen – vorausgesetzt, es stehen mehrere CPUs zur Verfügung.
Du kannst andere Aufgaben erledigen, während I/O-Operationen laufen – mithilfe mehrerer Threads oder sogar mit dem Main-Thread plus einem zusätzlichen Thread. Beispiel: Das Auslesen der Kameraframes und die Inferenz des Algorithmus werden von unterschiedlichen Threads übernommen. So muss der Algorithmus nicht auf das nächste Frame warten, und das Auslesen blockiert nicht, bis die Inferenz beendet ist.
Threads innerhalb desselben Prozesses können sich Speicher und Ressourcen des Main-Threads teilen.
Herausforderungen beim Threading
Python basiert in der Regel auf der CPython-Implementierung, die nur die Ausführung eines Threads zur selben Zeit erlaubt. Threading beschleunigt daher nicht jede Aufgabe. Der Hauptgrund dafür ist der Global Interpreter Lock (GIL).
Wenn du mehr über den GIL lernen willst, schau dir dieses Tutorial an.
Für CPU-intensive Aufgaben ist Threading meist nicht die beste Wahl. In solchen Fällen ist Multiprocessing oft sinnvoller.
Programme mit vielen Threads müssen schnell zwischen Threads wechseln. Deshalb ist sauberes Scheduling erforderlich, wenn du viele Threads einsetzt.
Ressourcenteilung kann problematisch sein, weil alle Threads denselben Speicher und die globalen Variablen teilen. Eine Operation in einem Thread kann Speicherfehler in einem anderen Thread verursachen, oder ein Thread bekommt nicht genug Speicher für seine Aufgabe.
Threading in Python
In Python gibt es das eingebaute Modul threading, das du direkt importieren kannst.
Da in Python fast alles ein Objekt ist, gilt das auch für Threads. Ein Thread kann
Daten halten,
in Datenstrukturen wie Dictionaries, Listen, Sets usw. gespeichert werden,
als Parameter an eine Funktion übergeben werden.
Ein Thread kann auch als Prozess ausgeführt werden.
Ein Thread in Python kann verschiedene Zustände haben, z. B.:
Warten,
Gesperrt.
Schauen wir uns nun an, wie du Threading in Python umsetzt.
Thread-Modul in Python 3
Beachte: Python 3 ist abwärtskompatibel zum thread-Modul aus Python 2.7. In Python 3 kannst du es als _thread importieren. Sehen wir uns dazu ein Beispiel an und verstehen das _thread-Modul.
import _thread #thread module importedimport time #time moduleBereitgestellt von
Definieren wir eine Funktion thread_delay mit zwei Parametern: dem Namen des Threads und der Verzögerung. In dieser Funktion wirst du:
Einen Zähler mit Null starten,
Mit einer while-Schleife drei Durchläufe ausführen,
Innerhalb der Schleife mit time.sleep() eine Verzögerung einbauen, um die Thread-Ausführung sichtbar zu machen (in Sekunden),
Den Zähler um 1 erhöhen,
Zur Kontrolle den Thread-Namen und die Zeit des jeweiligen Durchlaufs ausgeben.
Übergeben wir die Funktion thread_delay ohne Klammern und dazu die zwei Argumente, also Thread-Name und Verzögerung (damit du die sehr schnelle Thread-Ausführung sehen kannst).
_thread.start_new_thread(thread_delay,('t1',1))
_thread.start_new_thread(thread_delay,('t2',3))Bereitgestellt von
Am Output siehst du: Der Thread t1 startet zuerst. t2 wartet wegen der 3-Sekunden-Verzögerung. Sobald diese abgelaufen ist, wird t2 ausgeführt – während t1 nur 1 Sekunde Verzögerung hat.
Ändern wir nun die Verzögerung von t2 auf 5 Sekunden. Dadurch startet t2 erst, wenn t1 bereits fertig ist, denn t1 benötigt nur 3 Sekunden.
_thread.start_new_thread(thread_delay,('t1',1))
_thread.start_new_thread(thread_delay,('t2',5))Bereitgestellt von
Mit der Methode join wartest du, bis die Ausführung aller Threads abgeschlossen ist. Code nach join wird erst ausgeführt, wenn die Threads beendet sind.
t1 = threading.Thread(target=volume_cube, args=(2))
t2 = threading.Thread(target=volume_square, args=(3))Bereitgestellt von
t1.start()
t2.start()
t1.join()
t2.join()print("Thread execution is complete!")Bereitgestellt von
Thread execution is complete!
Exception in thread Thread-9:Traceback(most recent call last):
File "C:\Program Files\Anaconda3\lib\threading.py", line 926,in _bootstrap_inner
self.run()
File "C:\Program Files\Anaconda3\lib\threading.py", line 870,in run
self._target(*self._args,**self._kwargs)TypeError:volume_square() argument after * must be an iterable, not int
Exception in thread Thread-8:Traceback(most recent call last):
File "C:\Program Files\Anaconda3\lib\threading.py", line 926,in _bootstrap_inner
self.run()
File "C:\Program Files\Anaconda3\lib\threading.py", line 870,in run
self._target(*self._args,**self._kwargs)TypeError:volume_cube() argument after * must be an iterable, not int
Bereitgestellt von
Moment – was ist da passiert? Direkt nach dem Start tritt ein Fehler auf. Grund: Der Parameter args erwartet ein Tuple. Da volume_cube und volume_square jeweils nur einen Parameter erwarten, musst du im args-Parameter nach dem ersten Argument ein Komma setzen.
t1 = threading.Thread(target=volume_cube, args=(2,))
t2 = threading.Thread(target=volume_square, args=(3,))Bereitgestellt von
t1.start()
t2.start()
t1.join()
t2.join()print("Thread execution is complete!")Bereitgestellt von
Volume ofCube:8
Volume ofSquare:9
Thread execution is complete!Bereitgestellt von
Als Nächstes nutzen wir Threading als Subklasse.
Threading als Subklasse
In diesem Abschnitt lernst du, wie du aus der Thread-Klasse im threading-Modul eine Subklasse erstellst und daraus die Thread-Instanzen t1 und t2 anlegst.
Auch hier verwenden wir die Funktion thread_delay.
classDataCampThread(threading.Thread):def__init__(self, name, delay):
threading.Thread.__init__(self)
self.name = name
self.delay = delay
defrun(self):print('Starting Thread:', self.name)
thread_delay(self.name,self.delay)print('Execution of Thread:', self.name,'is complete!')
t1 = DataCampThread('t1',1)
t2 = DataCampThread('t2',3)
t1.start()
t2.start()
t1.join()
t2.join()print("Thread execution is complete!")Bereitgestellt von
Starting Thread: t1
Starting Thread: t2
t1 -------->1588089083.4879806
t1 -------->1588089084.489222
t1 -------->1588089085.4909666
Execution ofThread: t1 is complete!
t2 -------->1588089085.4979634
t2 -------->1588089088.499365
t2 -------->1588089091.5012596
Execution ofThread: t2 is complete!
Thread execution is complete!Bereitgestellt von
Was passiert hier Schritt für Schritt?
Du definierst eine Klasse DataCampThread und gibst ihr als Basisklasse threading.Thread mit. Damit erstellst du eine Subklasse aus dem threading-Modul und kannst alle Methoden der Klasse threading.Thread wie bei Vererbung nutzen.
Dann definierst du die Init-Methode der DataCampThread-Klasse und übergibst Name und Verzögerung. Das Init ist der Konstruktor – ähnlich den Parametern, die du der Klasse threading.Thread übergibst, nur eben hier für DataCampThread.
Als Nächstes initialisierst du die Init-Methode der Basisklasse threading.Thread und setzt Name und Verzögerung.
Du definierst die Methode run. Zur Erinnerung: Hier hast du die Methode start verwendet, die unter der Haube run aufruft. Da du die Basisklasse geerbt hast, darfst du run überschreiben. Wenn du also start aufrufst, greifen deine Änderungen in run.
Fazit
Glückwunsch – du hast das Tutorial abgeschlossen.
Dieses Tutorial war eine grundlegende Einführung in Threading in Python. Threading ist jedoch ein großes und wichtiges Thema, und einige Aspekte konnten wir hier nur anreißen. Sieh dir gern weitere Threading-Methoden wie active_count, current_thread usw. an.
Mach dich mit Python-Datenstrukturen vertraut: Lerne mehr über Datentypen und primitive sowie nicht-primitive Datenstrukturen wie Strings, Listen, Stapel usw.
Ein umfassendes Einführungs-Tutorial zu Python-Schleifen. Lerne und übe while- und for-Schleifen, verschachtelte Schleifen, die Schlüsselwörter break und continue, die Range-Funktion und vieles mehr!
Lerne mehr über Python-Lambda-Funktionen, wozu sie gut sind und wann man sie benutzt. Enthält praktische Beispiele und bewährte Methoden für eine effektive Umsetzung.
Wenn du gerade erst mit Python startest und mehr lernen willst, mach den Kurs Introduction to Data Science in Python von DataCamp.
Einführung
Threading ermöglicht es, verschiedene Teile eines Prozesses gleichzeitig auszuführen (Quelle: RealPython). Diese Teile sind in der Regel eigenständig und haben eine eigene Ausführungseinheit, gehören aber zum selben Prozess. Ein Prozess ist einfach ein laufendes Programm mit einzelnen Einheiten, die parallel laufen können. Beispiele: Ein Webbrowser ist ein Prozess, eine Anwendung, die mehrere Kameras gleichzeitig betreibt, ist ein Prozess; auch ein Videospiel ist ein Prozess.
Innerhalb eines Prozesses gibt es das Konzept des Multithreadings, bei dem mehrere Threads gemeinsam ein Ziel verfolgen. Der größte Vorteil von Threads ist, dass du Programmteile parallel laufen lassen kannst.
Verstehen wir Threading anhand eines Beispiels: Stell dir eine Anwendung vor, die die Anzahl der Autos zählt, die in das Parkhaus eines Einkaufszentrums ein- und ausfahren. Dein Aufbau umfasst mehrere Kameras, die Ein- und Ausfahrten überwachen und mit einem zentralen Gerät verbunden sind. Jede Kamera hat einen Algorithmus zur Überwachung des Verkehrsflusses, der zum selben Prozess gehört. Jede Kamera samt Algorithmus kann jedoch in einem eigenen Thread laufen. Sogar das Auslesen der Kameraframes und die Inferenz des Algorithmus auf diesen Frames können zwei getrennte Threads sein.
Ein weiteres Beispiel ist ein Videospiel, bei dem der Prozess Aufgaben parallel ausführen muss – etwa Grafik, Nutzerinteraktion und Netzwerkkommunikation (bei Multiplayer) – damit es jederzeit reaktionsschnell bleibt. Dafür nutzt man Multithreading, wobei jeder Thread eine unabhängige Aufgabe übernimmt.
Ein Thread hat seinen eigenen Ausführungsfluss, das heißt, im Prozess passieren mehrere Dinge gleichzeitig.
Wichtig: Jeder Prozess hat mindestens einen Thread, den
main thread. Selbst wenn du keine zusätzlichen Threads definierst, existiert der Main-Thread – also der Prozess selbst.Im obigen Diagramm siehst du einen Prozess mit dem Main-Thread (mit globalen Variablen) und drei Threads t1, t2 und t3. Jeder Thread hat eigene lokale Variablen und einen eigenen Ausführungsfluss. Die Threads teilen sich in der Regel die Ressourcen des Prozesses: Was dem Main-Thread zur Verfügung steht, wird auch mit t1, t2 und t3 geteilt. Alle Threads haben Zugriff auf globale Variablen und zusätzlich ihre lokalen.
Es gibt verschiedene Arten von Threads:
Schauen wir uns nun einige Vorteile von Threading in deinem Programm an:
Mit Multithreading kann ein Programm schneller ausführen – vorausgesetzt, es stehen mehrere CPUs zur Verfügung.
Du kannst andere Aufgaben erledigen, während I/O-Operationen laufen – mithilfe mehrerer Threads oder sogar mit dem Main-Thread plus einem zusätzlichen Thread. Beispiel: Das Auslesen der Kameraframes und die Inferenz des Algorithmus werden von unterschiedlichen Threads übernommen. So muss der Algorithmus nicht auf das nächste Frame warten, und das Auslesen blockiert nicht, bis die Inferenz beendet ist.
Herausforderungen beim Threading
Python basiert in der Regel auf der CPython-Implementierung, die nur die Ausführung eines Threads zur selben Zeit erlaubt. Threading beschleunigt daher nicht jede Aufgabe. Der Hauptgrund dafür ist der Global Interpreter Lock (GIL).
Wenn du mehr über den GIL lernen willst, schau dir dieses Tutorial an.
Für CPU-intensive Aufgaben ist Threading meist nicht die beste Wahl. In solchen Fällen ist Multiprocessing oft sinnvoller.
Programme mit vielen Threads müssen schnell zwischen Threads wechseln. Deshalb ist sauberes Scheduling erforderlich, wenn du viele Threads einsetzt.
Ressourcenteilung kann problematisch sein, weil alle Threads denselben Speicher und die globalen Variablen teilen. Eine Operation in einem Thread kann Speicherfehler in einem anderen Thread verursachen, oder ein Thread bekommt nicht genug Speicher für seine Aufgabe.
Threading in Python
In Python gibt es das eingebaute Modul
threading, das du direkt importieren kannst.Da in Python fast alles ein Objekt ist, gilt das auch für Threads. Ein Thread kann
Ein Thread kann auch als Prozess ausgeführt werden.
Ein Thread in Python kann verschiedene Zustände haben, z. B.:
Schauen wir uns nun an, wie du Threading in Python umsetzt.
Thread-Modul in Python 3
Beachte: Python 3 ist abwärtskompatibel zum
thread-Modul aus Python 2.7. In Python 3 kannst du es als_threadimportieren. Sehen wir uns dazu ein Beispiel an und verstehen das_thread-Modul.Definieren wir eine Funktion
thread_delaymit zwei Parametern: dem Namen des Threads und der Verzögerung. In dieser Funktion wirst du:time.sleep()eine Verzögerung einbauen, um die Thread-Ausführung sichtbar zu machen (in Sekunden),Um die obige Funktion in einem Thread laufen zu lassen, verwendest du die Methode
start_new_threadaus dem_thread-Modul.Werfen wir einen Blick in die Docstring von
start_new_thread.Übergeben wir die Funktion
thread_delayohne Klammern und dazu die zwei Argumente, also Thread-Name und Verzögerung (damit du die sehr schnelle Thread-Ausführung sehen kannst).Am Output siehst du: Der Thread
t1startet zuerst.t2wartet wegen der 3-Sekunden-Verzögerung. Sobald diese abgelaufen ist, wirdt2ausgeführt – währendt1nur 1 Sekunde Verzögerung hat.Ändern wir nun die Verzögerung von
t2auf 5 Sekunden. Dadurch startett2erst, wennt1bereits fertig ist, dennt1benötigt nur 3 Sekunden.Threading mit dem Threading-Modul umsetzen
Wir nutzen dasselbe Beispiel wie oben, diesmal aber mit dem Modul
threadingstatt_thread.Im
threading-Modul gibt es die KlasseThread, die in ähnlichem Geist wie die Funktionstart_new_threaddes_thread-Moduls funktioniert.Schauen wir in die Docstring der Klasse
Thread, sie nimmt mehrere Parameter wie group, target (z. B. eine Funktion), args usw.Im Konstruktor der Thread-Klasse übergibst du die Zielfunktion
thread_delayund deren Argumente.Um den Thread zu starten, verwendest du im
threading-Modul die Methodestart(), die den Thread ausführt.Mit der Methode
joinwartest du, bis die Ausführung aller Threads abgeschlossen ist. Code nachjoinwird erst ausgeführt, wenn die Threads beendet sind.Berechnen wir nun mit Threads das Volumen von Würfel und Quadrat – ganz unkompliziert.
Moment – was ist da passiert? Direkt nach dem Start tritt ein Fehler auf. Grund: Der Parameter
argserwartet ein Tuple. Davolume_cubeundvolume_squarejeweils nur einen Parameter erwarten, musst du imargs-Parameter nach dem ersten Argument ein Komma setzen.Als Nächstes nutzen wir Threading als Subklasse.
Threading als Subklasse
In diesem Abschnitt lernst du, wie du aus der Thread-Klasse im threading-Modul eine Subklasse erstellst und daraus die Thread-Instanzen
t1undt2anlegst.Auch hier verwenden wir die Funktion
thread_delay.Was passiert hier Schritt für Schritt?
Du definierst eine Klasse
DataCampThreadund gibst ihr als Basisklassethreading.Threadmit. Damit erstellst du eine Subklasse aus dem threading-Modul und kannst alle Methoden der Klassethreading.Threadwie bei Vererbung nutzen.Dann definierst du die Init-Methode der DataCampThread-Klasse und übergibst Name und Verzögerung. Das Init ist der Konstruktor – ähnlich den Parametern, die du der Klasse
threading.Threadübergibst, nur eben hier fürDataCampThread.Als Nächstes initialisierst du die Init-Methode der Basisklasse
threading.Threadund setzt Name und Verzögerung.Du definierst die Methode
run. Zur Erinnerung: Hier hast du die Methodestartverwendet, die unter der Hauberunaufruft. Da du die Basisklasse geerbt hast, darfst durunüberschreiben. Wenn du alsostartaufrufst, greifen deine Änderungen inrun.Fazit
Glückwunsch – du hast das Tutorial abgeschlossen.
Dieses Tutorial war eine grundlegende Einführung in Threading in Python. Threading ist jedoch ein großes und wichtiges Thema, und einige Aspekte konnten wir hier nur anreißen. Sieh dir gern weitere Threading-Methoden wie active_count, current_thread usw. an.
Wenn du tiefer einsteigen willst, lies auch Pythons Doku zu Thread-basierter Parallelisierung.
Wenn du gerade erst mit Python beginnst und mehr lernen willst, mach den Kurs Introduction to Data Science in Python von DataCamp.