Weiter zum Inhalt

Der ultimative Guide: Threading in Python Tutorial

Lerne die grundlegenden Konzepte von Threading kennen und wie du sie mit Python nutzt.
Aktualisiert 18. Sept. 2026  · 12 Min. lesen

Mit KI erkunden

ChatGPTClaudePerplexity

Wenn du gerade erst mit Python startest und mehr lernen willst, mach den Kurs Introduction to Data Science in Python von DataCamp.

graphic

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:

  • 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 imported
import time #time module

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.
def thread_delay(thread_name, delay):
    count = 0
    while count < 3:
        time.sleep(delay)
        count += 1
        print(thread_name, '-------->', time.time())

Um die obige Funktion in einem Thread laufen zu lassen, verwendest du die Methode start_new_thread aus dem _thread-Modul.

Werfen wir einen Blick in die Docstring von start_new_thread.

?_thread.start_new_thread
Threading in Python Tutorial

Ü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))
10916



t1 --------> 1588077856.4221454
t1 --------> 1588077857.4418247
t2 --------> 1588077858.422453
t1 --------> 1588077858.4431
t2 --------> 1588077861.4371448
t2 --------> 1588077864.438915

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))
14632



t1 --------> 1588078001.4087512
t1 --------> 1588078002.4272866
t1 --------> 1588078003.432218
t2 --------> 1588078005.4082909
t2 --------> 1588078010.4268317
t2 --------> 1588078015.4283602

Threading mit dem Threading-Modul umsetzen

Wir nutzen dasselbe Beispiel wie oben, diesmal aber mit dem Modul threading statt _thread.

import threading
import time
def thread_delay(thread_name, delay):
    count = 0
    while count < 3:
        time.sleep(delay)
        count += 1
        print(thread_name, '-------->', time.time())

Im threading-Modul gibt es die Klasse Thread, die in ähnlichem Geist wie die Funktion start_new_thread des _thread-Moduls funktioniert.

Schauen wir in die Docstring der Klasse Thread, sie nimmt mehrere Parameter wie group, target (z. B. eine Funktion), args usw.

?threading.Thread
Threading in Python Tutorial

Im Konstruktor der Thread-Klasse übergibst du die Zielfunktion thread_delay und deren Argumente.

t1 = threading.Thread(target=thread_delay, args=('t1', 1))
t2 = threading.Thread(target=thread_delay, args=('t2', 3))

Um den Thread zu starten, verwendest du im threading-Modul die Methode start(), die den Thread ausführt.

?t1.start
Threading in Python Tutorial
t1.start()
t2.start()
t1 --------> 1588081121.7790291
t1 --------> 1588081122.7962046
t2 --------> 1588081123.7789369
t1 --------> 1588081123.7980876
t2 --------> 1588081126.7961557
t2 --------> 1588081129.7995002

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.join
Threading in Python Tutorial
t1.start()
t2.start()

t1.join()
t2.join()

print("Thread execution is complete!")
t1 --------> 1588081798.7118263
t1 --------> 1588081799.7231226
t2 --------> 1588081800.7129223
t1 --------> 1588081800.730732
t2 --------> 1588081803.7298765
t2 --------> 1588081806.7309563
Thread execution is complete!

Berechnen wir nun mit Threads das Volumen von Würfel und Quadrat – ganz unkompliziert.

def volume_cube(a):
    print ("Volume of Cube:", a*a*a)
def volume_square(a):
    print ("Volume of Square:", a*a)
t1 = threading.Thread(target=volume_cube, args=(2))
t2 = threading.Thread(target=volume_square, args=(3))
t1.start()
t2.start()

t1.join()
t2.join()

print("Thread execution is complete!")
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

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,))
t1.start()
t2.start()

t1.join()
t2.join()

print("Thread execution is complete!")
Volume of Cube: 8
Volume of Square: 9
Thread execution is complete!

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.

class DataCampThread(threading.Thread):
    def __init__(self, name, delay):
        threading.Thread.__init__(self)
        self.name = name
        self.delay = delay


    def run(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!")
Starting Thread: t1
Starting Thread: t2
t1 --------> 1588089083.4879806
t1 --------> 1588089084.489222
t1 --------> 1588089085.4909666
Execution of Thread: t1 is complete!
t2 --------> 1588089085.4979634
t2 --------> 1588089088.499365
t2 --------> 1588089091.5012596
Execution of Thread: t2 is complete!
Thread execution is complete!

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.

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.

Themen
Python

Python-Kurse

Kurs

Einführung in Python

4 Std.
7M
Lerne in nur vier Stunden die Grundlagen der Datenanalyse mit Python und entdecke beliebte Python-Pakete.
Details anzeigenRight Arrow
Kurs Starten
Mehr anzeigenRight Arrow