threading — Thread-basierte Parallelität

Quellcode: Lib/threading.py


Dieses Modul erstellt höherstufige Thread-Schnittstellen auf Basis des Moduls auf niedrigerer Ebene _thread.

Verfügbarkeit: nicht WASI.

Dieses Modul funktioniert nicht oder ist nicht auf WebAssembly verfügbar. Weitere Informationen finden Sie unter WebAssembly-Plattformen.

Einleitung

Das Modul threading bietet eine Möglichkeit, mehrere Threads (kleinere Einheiten eines Prozesses) innerhalb eines einzigen Prozesses gleichzeitig auszuführen. Es ermöglicht die Erstellung und Verwaltung von Threads, wodurch Aufgaben parallel ausgeführt werden können, wobei der Speicherplatz geteilt wird. Threads sind besonders nützlich, wenn Aufgaben E/A-gebunden sind, wie z. B. Dateioperationen oder Netzwerkanfragen, bei denen viel Zeit mit dem Warten auf externe Ressourcen verbracht wird.

Ein typischer Anwendungsfall für threading ist die Verwaltung eines Pools von Worker-Threads, die mehrere Aufgaben gleichzeitig verarbeiten können. Hier ist ein einfaches Beispiel für die Erstellung und den Start von Threads mit Thread

import threading
import time

def crawl(link, delay=3):
    print(f"crawl started for {link}")
    time.sleep(delay)  # Blocking I/O (simulating a network request)
    print(f"crawl ended for {link}")

links = [
    "https://pythonlang.de",
    "https://docs.pythonlang.de",
    "https://peps.pythonlang.de",
]

# Start threads for each link
threads = []
for link in links:
    # Using `args` to pass positional arguments and `kwargs` for keyword arguments
    t = threading.Thread(target=crawl, args=(link,), kwargs={"delay": 2})
    threads.append(t)

# Start each thread
for t in threads:
    t.start()

# Wait for all threads to finish
for t in threads:
    t.join()

Geändert in Version 3.7: Dieses Modul war früher optional, es ist jetzt immer verfügbar.

Siehe auch

concurrent.futures.ThreadPoolExecutor bietet eine höherstufige Schnittstelle, um Aufgaben an einen Hintergrund-Thread zu übergeben, ohne die Ausführung des aufrufenden Threads zu blockieren, und um deren Ergebnisse bei Bedarf abrufen zu können.

queue bietet eine Thread-sichere Schnittstelle für den Datenaustausch zwischen laufenden Threads.

asyncio bietet einen alternativen Ansatz, um Konkurrenz auf Aufgabenebene zu erreichen, ohne dass mehrere Betriebssystem-Threads verwendet werden müssen.

Hinweis

In der Python 2.x-Reihe enthielt dieses Modul camelCase-Namen für einige Methoden und Funktionen. Diese sind ab Python 3.10 veraltet, werden aber weiterhin zur Kompatibilität mit Python 2.5 und niedriger unterstützt.

CPython Implementierungsdetails: In CPython kann aufgrund des Global Interpreter Lock (GIL) immer nur ein Thread Python-Code gleichzeitig ausführen (obwohl bestimmte leistungsorientierte Bibliotheken diese Einschränkung überwinden können). Wenn Ihre Anwendung die Rechenressourcen von Multi-Core-Maschinen besser nutzen möchte, wird die Verwendung von multiprocessing oder concurrent.futures.ProcessPoolExecutor empfohlen. Threading ist jedoch weiterhin ein geeignetes Modell, wenn Sie mehrere E/A-gebundene Aufgaben gleichzeitig ausführen möchten.

GIL und Leistungsüberlegungen

Im Gegensatz zum Modul multiprocessing, das separate Prozesse verwendet, um den Global Interpreter Lock (GIL) zu umgehen, arbeitet das Modul threading innerhalb eines einzigen Prozesses, was bedeutet, dass alle Threads denselben Speicherplatz teilen. Der GIL begrenzt jedoch die Leistungssteigerung durch Threading bei CPU-gebundenen Aufgaben, da zu einem Zeitpunkt nur ein Thread Python-Bytecode ausführen kann. Trotzdem bleiben Threads ein nützliches Werkzeug, um in vielen Szenarien Konkurrenz zu erzielen.

Ab Python 3.13 können freie Threading-Builds die GIL deaktivieren und so echte parallele Ausführung von Threads ermöglichen, aber diese Funktion ist standardmäßig nicht verfügbar (siehe PEP 703).

Referenz

Dieses Modul definiert die folgenden Funktionen

threading.active_count()

Gibt die Anzahl der aktuell aktiven Thread-Objekte zurück. Die zurückgegebene Anzahl ist gleich der Länge der Liste, die von enumerate() zurückgegeben wird.

Die Funktion activeCount ist ein veralteter Alias für diese Funktion.

threading.current_thread()

Gibt das aktuelle Thread-Objekt zurück, das dem Thread of Control des Aufrufers entspricht. Wenn der Thread of Control des Aufrufers nicht über das Modul threading erstellt wurde, wird ein Dummy-Thread-Objekt mit eingeschränkter Funktionalität zurückgegeben.

Die Funktion currentThread ist ein veralteter Alias für diese Funktion.

threading.excepthook(args, /)

Behandelt eine nicht abgefangene Ausnahme, die von Thread.run() ausgelöst wurde.

Das Argument args hat die folgenden Attribute:

  • exc_type: Exception-Typ.

  • exc_value: Ausnahme-Wert, kann None sein.

  • exc_traceback: Ausnahme-Traceback, kann None sein.

  • thread: Thread, der die Ausnahme ausgelöst hat, kann None sein.

Wenn exc_type SystemExit ist, wird die Ausnahme stillschweigend ignoriert. Andernfalls wird die Ausnahme auf sys.stderr ausgegeben.

Wenn diese Funktion eine Ausnahme auslöst, wird sys.excepthook() aufgerufen, um sie zu behandeln.

threading.excepthook() kann überschrieben werden, um zu steuern, wie nicht abgefangene Ausnahmen behandelt werden, die von Thread.run() ausgelöst werden.

Das Speichern von exc_value mit einem benutzerdefinierten Hook kann zu einem Referenzzyklus führen. Es sollte explizit gelöscht werden, um den Referenzzyklus zu brechen, wenn die Ausnahme nicht mehr benötigt wird.

Das Speichern von thread mit einem benutzerdefinierten Hook kann ihn wiederbeleben, wenn er auf ein Objekt gesetzt wird, das gerade finalisiert wird. Vermeiden Sie das Speichern von thread nach Abschluss des benutzerdefinierten Hooks, um das Wiederbeleben von Objekten zu vermeiden.

Siehe auch

sys.excepthook() behandelt nicht abgefangene Ausnahmen.

Hinzugefügt in Version 3.8.

threading.__excepthook__

Enthält den ursprünglichen Wert von threading.excepthook(). Er wird gespeichert, damit der ursprüngliche Wert wiederhergestellt werden kann, falls er durch fehlerhafte oder alternative Objekte ersetzt wird.

Hinzugefügt in Version 3.10.

threading.get_ident()

Gibt die „Thread-Identität“ des aktuellen Threads zurück. Dies ist eine nicht-null ganze Zahl. Ihr Wert hat keine direkte Bedeutung; er ist als magischer Cookie gedacht, der z. B. zur Indizierung eines Wörterbuchs von Thread-spezifischen Daten verwendet werden kann. Thread-Identitäten können wiederverwendet werden, wenn ein Thread beendet wird und ein anderer Thread erstellt wird.

Hinzugefügt in Version 3.3.

threading.get_native_id()

Gibt die native Ganzzahl-Thread-ID des aktuellen Threads zurück, die vom Kernel zugewiesen wurde. Dies ist eine nicht-negative Ganzzahl. Ihr Wert kann verwendet werden, um diesen speziellen Thread systemweit eindeutig zu identifizieren (bis der Thread beendet wird, danach kann der Wert vom Betriebssystem wiederverwendet werden).

Verfügbarkeit: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX, DragonFlyBSD, GNU/kFreeBSD.

Hinzugefügt in Version 3.8.

Geändert in Version 3.13: Unterstützung für GNU/kFreeBSD hinzugefügt.

threading.enumerate()

Gibt eine Liste aller aktuell aktiven Thread-Objekte zurück. Die Liste enthält Daemon-Threads und Dummy-Thread-Objekte, die von current_thread() erstellt wurden. Sie schließt beendete Threads und noch nicht gestartete Threads aus. Der Hauptthread ist jedoch immer Teil des Ergebnisses, auch wenn er beendet ist.

threading.main_thread()

Gibt das Haupt- Thread-Objekt zurück. Unter normalen Umständen ist der Hauptthread der Thread, von dem aus der Python-Interpreter gestartet wurde.

Hinzugefügt in Version 3.4.

threading.settrace(func)

Setzt eine Trace-Funktion für alle Threads, die aus dem Modul threading gestartet wurden. func wird für jeden Thread an sys.settrace() übergeben, bevor dessen run()-Methode aufgerufen wird.

threading.settrace_all_threads(func)

Setzt eine Trace-Funktion für alle Threads, die aus dem Modul threading gestartet wurden, sowie für alle aktuell ausgeführten Python-Threads.

func wird für jeden Thread an sys.settrace() übergeben, bevor dessen run()-Methode aufgerufen wird.

Hinzugefügt in Version 3.12.

threading.gettrace()

Ruft die Trace-Funktion ab, die mit settrace() gesetzt wurde.

Hinzugefügt in Version 3.10.

threading.setprofile(func)

Setzt eine Profiler-Funktion für alle Threads, die aus dem Modul threading gestartet wurden. func wird für jeden Thread an sys.setprofile() übergeben, bevor dessen run()-Methode aufgerufen wird.

threading.setprofile_all_threads(func)

Setzt eine Profiler-Funktion für alle Threads, die aus dem Modul threading gestartet wurden, sowie für alle aktuell ausgeführten Python-Threads.

func wird für jeden Thread an sys.setprofile() übergeben, bevor dessen run()-Methode aufgerufen wird.

Hinzugefügt in Version 3.12.

threading.getprofile()

Ruft die Profiler-Funktion ab, die mit setprofile() gesetzt wurde.

Hinzugefügt in Version 3.10.

threading.stack_size([size])

Gibt die Thread-Stackgröße zurück, die beim Erstellen neuer Threads verwendet wird. Das optionale Argument size gibt die Stackgröße an, die für nachfolgend erstellte Threads verwendet werden soll, und muss 0 (Standardwert der Plattform oder konfigurierter Standardwert) oder eine positive Ganzzahl von mindestens 32.768 (32 KiB) sein. Wenn size nicht angegeben ist, wird 0 verwendet. Wenn die Änderung der Thread-Stackgröße nicht unterstützt wird, wird ein RuntimeError ausgelöst. Wenn die angegebene Stackgröße ungültig ist, wird ein ValueError ausgelöst und die Stackgröße nicht geändert. 32 KiB ist derzeit die minimal unterstützte Stackgröße, um ausreichend Stackplatz für den Interpreter selbst zu gewährleisten. Beachten Sie, dass einige Plattformen möglicherweise spezielle Einschränkungen für Stackgrößenwerte haben, z. B. eine Mindest-Stackgröße von über 32 KiB oder die Erfordernis der Zuweisung in Vielfachen der System-Speicherseitengröße – die Dokumentation der Plattform sollte für weitere Informationen konsultiert werden (4 KiB Seiten sind üblich; die Verwendung von Vielfachen von 4096 für die Stackgröße ist der empfohlene Ansatz, wenn keine spezifischeren Informationen vorliegen).

Verfügbarkeit: Windows, pthreads.

Unix-Plattformen mit POSIX-Threads-Unterstützung.

Dieses Modul definiert auch die folgende Konstante:

threading.TIMEOUT_MAX

Der maximal zulässige Wert für den Parameter timeout von blockierenden Funktionen (Lock.acquire(), RLock.acquire(), Condition.wait() usw.). Die Angabe eines Zeitlimits, das größer als dieser Wert ist, löst einen OverflowError aus.

Hinzugefügt in Version 3.2.

Dieses Modul definiert eine Reihe von Klassen, die in den folgenden Abschnitten detailliert beschrieben werden.

Das Design dieses Moduls basiert lose auf dem Java-Threading-Modell. Während Java jedoch Locks und Bedingungsvariablen zum grundlegenden Verhalten jedes Objekts macht, sind sie in Python separate Objekte. Die Thread-Klasse von Python unterstützt eine Teilmenge des Verhaltens von Java’s Thread-Klasse; derzeit gibt es keine Prioritäten, keine Thread-Gruppen und Threads können nicht zerstört, gestoppt, suspendiert, fortgesetzt oder unterbrochen werden. Die statischen Methoden der Java-Thread-Klasse werden, wenn implementiert, auf Modul-Ebene Funktionen abgebildet.

Alle unten beschriebenen Methoden werden atomar ausgeführt.

Thread-lokale Daten

Thread-lokale Daten sind Daten, deren Werte Thread-spezifisch sind. Wenn Sie Daten haben, die lokal zu einem Thread sein sollen, erstellen Sie ein local-Objekt und verwenden Sie dessen Attribute.

>>> mydata = local()
>>> mydata.number = 42
>>> mydata.number
42

Sie können auch auf das Wörterbuch des local-Objekts zugreifen.

>>> mydata.__dict__
{'number': 42}
>>> mydata.__dict__.setdefault('widgets', [])
[]
>>> mydata.widgets
[]

Wenn wir in einem anderen Thread auf die Daten zugreifen:

>>> log = []
>>> def f():
...     items = sorted(mydata.__dict__.items())
...     log.append(items)
...     mydata.number = 11
...     log.append(mydata.number)

>>> import threading
>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()
>>> log
[[], 11]

erhalten wir andere Daten. Außerdem wirken sich Änderungen, die im anderen Thread vorgenommen werden, nicht auf die Daten aus, die in diesem Thread sichtbar sind.

>>> mydata.number
42

Natürlich sind Werte, die Sie von einem local-Objekt erhalten, einschließlich ihres __dict__-Attributs, für den Thread gültig, der zum Zeitpunkt des Lesens des Attributs aktuell war. Aus diesem Grund möchten Sie diese Werte im Allgemeinen nicht zwischen Threads speichern, da sie nur für den Thread gelten, von dem sie stammen.

Sie können benutzerdefinierte local-Objekte erstellen, indem Sie die Klasse local ableiten.

>>> class MyLocal(local):
...     number = 2
...     def __init__(self, /, **kw):
...         self.__dict__.update(kw)
...     def squared(self):
...         return self.number ** 2

Dies kann nützlich sein, um Standardwerte, Methoden und Initialisierung zu unterstützen. Beachten Sie, dass, wenn Sie eine __init__()-Methode definieren, diese jedes Mal aufgerufen wird, wenn das local-Objekt in einem separaten Thread verwendet wird. Dies ist notwendig, um das Wörterbuch jedes Threads zu initialisieren.

Wenn wir nun ein local-Objekt erstellen.

>>> mydata = MyLocal(color='red')

haben wir eine Standardanzahl.

>>> mydata.number
2

eine anfängliche Farbe.

>>> mydata.color
'red'
>>> del mydata.color

Und eine Methode, die auf den Daten operiert.

>>> mydata.squared()
4

Wie zuvor können wir in einem separaten Thread auf die Daten zugreifen.

>>> log = []
>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()
>>> log
[[('color', 'red')], 11]

ohne die Daten dieses Threads zu beeinträchtigen.

>>> mydata.number
2
>>> mydata.color
Traceback (most recent call last):
...
AttributeError: 'MyLocal' object has no attribute 'color'

Beachten Sie, dass Unterklassen __slots__ definieren können, diese sind jedoch nicht Thread-lokal. Sie werden zwischen Threads geteilt.

>>> class MyLocal(local):
...     __slots__ = 'number'

>>> mydata = MyLocal()
>>> mydata.number = 42
>>> mydata.color = 'red'

Daher beeinflusst der separate Thread.

>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()

was wir sehen.

>>> mydata.number
11
class threading.local

Eine Klasse, die Thread-lokale Daten repräsentiert.

Thread-Objekte

Die Klasse Thread repräsentiert eine Aktivität, die in einem separaten Kontrollfluss ausgeführt wird. Es gibt zwei Möglichkeiten, die Aktivität anzugeben: durch Übergabe eines aufrufbaren Objekts an den Konstruktor oder durch Überschreiben der Methode run() in einer Unterklasse. Keine anderen Methoden (außer dem Konstruktor) sollten in einer Unterklasse überschrieben werden. Mit anderen Worten, überschreiben Sie *nur* die Methoden __init__() und run() dieser Klasse.

Sobald ein Thread-Objekt erstellt wurde, muss seine Aktivität durch Aufruf der Methode start() des Threads gestartet werden. Dies ruft die Methode run() in einem separaten Kontrollfluss auf.

Sobald die Aktivität des Threads gestartet ist, gilt der Thread als „lebendig“. Er ist nicht mehr lebendig, wenn seine Methode run() beendet wird – entweder normal oder durch Auslösen einer nicht abgefangenen Ausnahme. Die Methode is_alive() prüft, ob der Thread lebendig ist.

Andere Threads können die Methode join() eines Threads aufrufen. Dies blockiert den aufrufenden Thread, bis der Thread, dessen Methode join() aufgerufen wurde, beendet ist.

Ein Thread hat einen Namen. Der Name kann dem Konstruktor übergeben und über das Attribut name gelesen oder geändert werden.

Wenn die Methode run() eine Ausnahme auslöst, wird threading.excepthook() aufgerufen, um sie zu behandeln. Standardmäßig ignoriert threading.excepthook() SystemExit stillschweigend.

Ein Thread kann als „Daemon-Thread“ markiert werden. Die Bedeutung dieses Flags ist, dass das gesamte Python-Programm beendet wird, wenn nur noch Daemon-Threads übrig sind. Der anfängliche Wert wird vom erstellenden Thread übernommen. Das Flag kann über die Eigenschaft daemon oder das daemon-Argument des Konstruktors gesetzt werden.

Hinweis

Daemon-Threads werden beim Herunterfahren abrupt beendet. Ihre Ressourcen (wie offene Dateien, Datenbanktransaktionen usw.) werden möglicherweise nicht ordnungsgemäß freigegeben. Wenn Sie möchten, dass Ihre Threads ordnungsgemäß beendet werden, machen Sie sie zu Nicht-Daemon-Threads und verwenden Sie einen geeigneten Signalisierungsmechanismus wie ein Event.

Es gibt ein „Hauptthread“-Objekt; dies entspricht dem anfänglichen Kontrollfluss im Python-Programm. Es ist kein Daemon-Thread.

Es besteht die Möglichkeit, dass „Dummy-Thread-Objekte“ erstellt werden. Dies sind Thread-Objekte, die „Alien-Threads“ entsprechen, d. h. Threads, die außerhalb des threading-Moduls gestartet wurden, z. B. direkt aus C-Code. Dummy-Thread-Objekte haben eine eingeschränkte Funktionalität; sie gelten immer als lebendig und als Daemon-Threads und können nicht joined werden. Sie werden niemals gelöscht, da es unmöglich ist, die Beendigung von Alien-Threads zu erkennen.

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None, context=None)

Dieser Konstruktor sollte immer mit Schlüsselwortargumenten aufgerufen werden. Die Argumente sind:

group sollte None sein; reserviert für zukünftige Erweiterungen, wenn eine Klasse ThreadGroup implementiert wird.

target ist das aufrufbare Objekt, das von der Methode run() aufgerufen wird. Standardmäßig None, was bedeutet, dass nichts aufgerufen wird.

name ist der Name des Threads. Standardmäßig wird ein eindeutiger Name der Form „Thread-N“ erstellt, wobei N eine kleine Dezimalzahl ist, oder „Thread-N (target)“, wobei „target“ target.__name__ ist, wenn das Argument target angegeben ist.

args ist eine Liste oder ein Tupel von Argumenten für den Target-Aufruf. Standardmäßig ().

kwargs ist ein Wörterbuch von Schlüsselwortargumenten für den Target-Aufruf. Standardmäßig {}.

Wenn daemon nicht None ist, legt es explizit fest, ob der Thread ein Daemon-Thread ist. Wenn None (der Standardwert), wird die Daemon-Eigenschaft vom aktuellen Thread übernommen.

context ist der Context-Wert, der beim Starten des Threads verwendet wird. Der Standardwert ist None, was bedeutet, dass das Flag sys.flags.thread_inherit_context das Verhalten steuert. Wenn das Flag wahr ist, starten Threads mit einer Kopie des Kontexts des Aufrufers von start(). Wenn falsch, starten sie mit einem leeren Kontext. Um explizit mit einem leeren Kontext zu starten, übergeben Sie eine neue Instanz von Context(). Um explizit mit einer Kopie des aktuellen Kontexts zu starten, übergeben Sie den Wert von copy_context(). Das Flag ist standardmäßig wahr bei freien Threading-Builds und andernfalls falsch.

Wenn die Unterklasse den Konstruktor überschreibt, muss sie sicherstellen, dass der Konstruktor der Basisklasse (Thread.__init__()) aufgerufen wird, bevor sie weitere Aktionen am Thread durchführt.

Geändert in Version 3.3: Das Argument daemon hinzugefügt.

Geändert in Version 3.10: Verwendet den Namen target, wenn das Argument name weggelassen wird.

Geändert in Version 3.14: Das Argument context hinzugefügt.

start()

Startet die Aktivität des Threads.

Sie darf höchstens einmal pro Thread-Objekt aufgerufen werden. Sie veranlasst, dass die Methode run() des Objekts in einem separaten Kontrollfluss aufgerufen wird.

Diese Methode löst einen RuntimeError aus, wenn sie mehr als einmal für dasselbe Thread-Objekt aufgerufen wird.

Wenn unterstützt, wird der Betriebssystem-Thread-Name auf threading.Thread.name gesetzt. Der Name kann je nach den Beschränkungen des Betriebssystem-Thread-Namens gekürzt werden.

Geändert in Version 3.14: Der Betriebssystem-Thread-Name wird gesetzt.

run()

Methode, die die Aktivität des Threads repräsentiert.

Sie können diese Methode in einer Unterklasse überschreiben. Die Standardmethode run() ruft das an den Konstruktor des Objekts übergebene aufrufbare Objekt als target-Argument auf, falls vorhanden, wobei positionsbezogene und schlüsselwortbasierte Argumente aus den args- und kwargs-Argumenten stammen.

Die Verwendung einer Liste oder eines Tupels als args-Argument, das an Thread übergeben wird, kann denselben Effekt erzielen.

Beispiel

>>> from threading import Thread
>>> t = Thread(target=print, args=[1])
>>> t.run()
1
>>> t = Thread(target=print, args=(1,))
>>> t.run()
1
join(timeout=None)

Wartet, bis der Thread beendet ist. Dies blockiert den aufrufenden Thread, bis der Thread, dessen Methode join() aufgerufen wurde, beendet ist – entweder normal oder durch eine nicht abgefangene Ausnahme – oder bis die optionale Zeitüberschreitung eintritt.

Wenn das timeout-Argument vorhanden und nicht None ist, sollte es eine Gleitkommazahl sein, die eine Zeitüberschreitung für die Operation in Sekunden (oder Bruchteilen davon) angibt. Da join() immer None zurückgibt, müssen Sie is_alive() nach dem Aufruf von join() aufrufen, um zu entscheiden, ob eine Zeitüberschreitung stattgefunden hat – wenn der Thread noch lebt, ist der Aufruf von join() abgelaufen.

Wenn das timeout-Argument nicht vorhanden oder None ist, wird die Operation blockiert, bis der Thread beendet ist.

Ein Thread kann mehrmals gejoined werden.

join() löst einen RuntimeError aus, wenn versucht wird, den aktuellen Thread zu joinen, da dies zu einer Verklemmung führen würde. Es ist auch ein Fehler, einen Thread zu joinen, bevor er gestartet wurde, und Versuche, dies zu tun, lösen dieselbe Ausnahme aus.

Wenn versucht wird, einen laufenden Daemon-Thread in späten Phasen des Interpreter-Shutdowns zu joinen, löst join() einen PythonFinalizationError aus.

Geändert in Version 3.14: Kann PythonFinalizationError auslösen.

name

Ein String, der nur zur Identifizierung verwendet wird. Er hat keine Semantik. Mehreren Threads können dieselben Namen gegeben werden. Der anfängliche Name wird vom Konstruktor festgelegt.

Auf einigen Plattformen wird der Thread-Name auf Betriebssystemebene festgelegt, wenn der Thread startet, so dass er in Task-Managern sichtbar ist. Dieser Name kann gekürzt werden, um auf ein systemspezifisches Limit zu passen (z. B. 15 Bytes unter Linux oder 63 Bytes unter macOS).

Änderungen an name spiegeln sich nur auf Betriebssystemebene wider, wenn der aktuell laufende Thread umbenannt wird. (Das Setzen des name-Attributs eines anderen Threads aktualisiert nur das Python Thread-Objekt.)

getName()
setName()

Veraltete Getter/Setter-API für name; verwenden Sie es stattdessen direkt als Eigenschaft.

Veraltet seit Version 3.10.

ident

Die 'Thread-ID' dieses Threads oder None, wenn der Thread nicht gestartet wurde. Dies ist eine ganzzahlige Zahl ungleich Null. Siehe die Funktion get_ident(). Thread-IDs können wiederverwendet werden, wenn ein Thread beendet wird und ein anderer Thread erstellt wird. Die ID ist auch nach Beendigung des Threads verfügbar.

native_id

Die Thread-ID (TID) dieses Threads, wie vom Betriebssystem (Kernel) zugewiesen. Dies ist eine nicht-negative Ganzzahl oder None, wenn der Thread nicht gestartet wurde. Siehe die Funktion get_native_id(). Dieser Wert kann verwendet werden, um diesen bestimmten Thread systemweit eindeutig zu identifizieren (bis der Thread beendet ist, danach kann der Wert vom Betriebssystem wiederverwendet werden).

Hinweis

Ähnlich wie Prozess-IDs sind Thread-IDs nur gültig (garantiert eindeutig systemweit) von dem Zeitpunkt, an dem der Thread erstellt wird, bis der Thread beendet wurde.

Verfügbarkeit: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX, DragonFlyBSD.

Hinzugefügt in Version 3.8.

is_alive()

Gibt zurück, ob der Thread aktiv ist.

Diese Methode gibt True zurück, unmittelbar bevor die Methode run() beginnt, bis unmittelbar nach Beendigung der Methode run(). Die Modul-Funktion enumerate() gibt eine Liste aller aktiven Threads zurück.

daemon

Ein boolescher Wert, der angibt, ob dieser Thread ein Daemon-Thread ist (True) oder nicht (False). Dies muss gesetzt werden, bevor start() aufgerufen wird, andernfalls wird ein RuntimeError ausgelöst. Sein anfänglicher Wert wird vom erzeugenden Thread übernommen; der Hauptthread ist kein Daemon-Thread und daher sind alle im Hauptthread erzeugten Threads standardmäßig auf daemon = False gesetzt.

Das gesamte Python-Programm wird beendet, wenn keine aktiven Nicht-Daemon-Threads mehr übrig sind.

isDaemon()
setDaemon()

Veraltete Getter/Setter-API für daemon; verwenden Sie es stattdessen direkt als Eigenschaft.

Veraltet seit Version 3.10.

Lock-Objekte

Ein primitiver Lock ist ein Synchronisationsprimitiv, das keinen bestimmten Thread besitzt, wenn es gesperrt ist. In Python ist es derzeit das am niedrigsten level synchronisationsprimitiv, das verfügbar ist, direkt implementiert vom _thread Erweiterungsmodul.

Ein primitiver Lock befindet sich in einem von zwei Zuständen: "locked" oder "unlocked". Er wird im ungesperrten Zustand erstellt. Er hat zwei grundlegende Methoden: acquire() und release(). Wenn der Zustand unlocked ist, ändert acquire() den Zustand zu locked und kehrt sofort zurück. Wenn der Zustand locked ist, blockiert acquire(), bis ein Aufruf von release() in einem anderen Thread ihn zu unlocked ändert, dann setzt der Aufruf von acquire() ihn wieder auf locked und kehrt zurück. Die Methode release() sollte nur im gesperrten Zustand aufgerufen werden; sie ändert den Zustand zu unlocked und kehrt sofort zurück. Wenn versucht wird, einen ungesperrten Lock freizugeben, wird ein RuntimeError ausgelöst.

Locks unterstützen auch das Kontextmanagementprotokoll.

Wenn mehr als ein Thread in acquire() blockiert und darauf wartet, dass der Zustand unlocked wird, wird nur ein Thread fortgesetzt, wenn ein Aufruf von release() den Zustand auf unlocked zurücksetzt; welcher der wartenden Threads fortgesetzt wird, ist nicht definiert und kann je nach Implementierung variieren.

Alle Methoden werden atomar ausgeführt.

class threading.Lock

Die Klasse, die primitive Lock-Objekte implementiert. Sobald ein Thread einen Lock erworben hat, blockieren nachfolgende Versuche, ihn zu erwerben, bis er freigegeben wird; jeder Thread kann ihn freigeben.

Geändert in Version 3.13: Lock ist jetzt eine Klasse. In früheren Pythons war Lock eine Factory-Funktion, die eine Instanz des zugrundeliegenden privaten Lock-Typs zurückgab.

acquire(blocking=True, timeout=-1)

Einen Lock erwerben, blockierend oder nicht blockierend.

Wenn mit dem blocking-Argument auf True (Standard) aufgerufen, blockiert, bis der Lock entsperrt ist, dann auf gesperrt gesetzt und True zurückgibt.

Wenn mit dem blocking-Argument auf False aufgerufen, blockiert nicht. Wenn ein Aufruf mit blocking auf True blockieren würde, kehrt er sofort False zurück; andernfalls wird der Lock auf gesperrt gesetzt und True zurückgegeben.

Wenn mit dem Gleitkomma-timeout-Argument, das auf einen positiven Wert gesetzt ist, aufgerufen, blockiert für höchstens die Anzahl der durch timeout angegebenen Sekunden und solange, bis der Lock nicht erworben werden kann. Ein timeout-Argument von -1 gibt eine unbegrenzte Wartezeit an. Es ist verboten, ein timeout anzugeben, wenn blocking auf False gesetzt ist.

Der Rückgabewert ist True, wenn der Lock erfolgreich erworben wurde, False, wenn nicht (z. B. wenn das timeout abgelaufen ist).

Geändert in Version 3.2: Der Parameter timeout ist neu.

Geändert in Version 3.2: Der Erwerb von Locks kann nun durch Signale auf POSIX unterbrochen werden, wenn die zugrunde liegende Threading-Implementierung dies unterstützt.

Geändert in Version 3.14: Der Erwerb von Locks kann nun unter Windows durch Signale unterbrochen werden.

release()

Einen Lock freigeben. Dies kann von jedem Thread aus erfolgen, nicht nur von dem Thread, der den Lock erworben hat.

Wenn der Lock gesperrt ist, wird er auf ungesperrt zurückgesetzt und kehrt zurück. Wenn andere Threads auf die Entsperrung des Locks warten, wird genau einer von ihnen fortgesetzt.

Wenn auf einen ungesperrten Lock aufgerufen, wird ein RuntimeError ausgelöst.

Es gibt keinen Rückgabewert.

locked()

Gibt True zurück, wenn der Lock erworben ist.

RLock-Objekte

Ein reentrater Lock ist ein Synchronisationsprimitiv, das vom selben Thread mehrmals erworben werden kann. Intern verwendet er zusätzlich zum "locked/unlocked"-Zustand, der von primitiven Locks verwendet wird, die Konzepte von "besitzendem Thread" und "Rekursionsebene". Im gesperrten Zustand besitzt ein Thread den Lock; im ungesperrten Zustand besitzt kein Thread ihn.

Threads rufen die Methode acquire() eines Locks auf, um ihn zu sperren, und seine Methode release(), um ihn zu entsperren.

Hinweis

Reentrante Locks unterstützen das Kontextmanagementprotokoll, daher wird empfohlen, with anstelle von manuellen Aufrufen von acquire() und release() zu verwenden, um das Erwerben und Freigeben des Locks für einen Codeblock zu handhaben.

RLock's acquire()/release() Aufrufpaare können verschachtelt sein, im Gegensatz zu Lock's acquire()/release(). Nur das letzte release() (das release() des äußersten Paares) setzt den Lock in den ungesperrten Zustand zurück und erlaubt es einem anderen Thread, der in acquire() blockiert, fortzufahren.

acquire()/release() müssen paarweise verwendet werden: jedes Erwerben muss ein Freigeben im Thread haben, der den Lock erworben hat. Das Versäumnis, Release so oft wie der Lock erworben wurde aufzurufen, kann zu Deadlocks führen. Ziehen Sie in Betracht, RLock als Kontextmanager zu verwenden, anstatt acquire/release direkt aufzurufen.

class threading.RLock

Diese Klasse implementiert reentrante Lock-Objekte. Ein reentrater Lock muss vom Thread freigegeben werden, der ihn erworben hat. Sobald ein Thread einen reentratren Lock erworben hat, kann derselbe Thread ihn erneut erwerben, ohne zu blockieren; der Thread muss ihn für jede Erwerbung einmal freigeben.

Beachten Sie, dass RLock tatsächlich eine Factory-Funktion ist, die eine Instanz der effizientesten Version der konkreten RLock-Klasse zurückgibt, die von der Plattform unterstützt wird.

acquire(blocking=True, timeout=-1)

Einen Lock erwerben, blockierend oder nicht blockierend.

Siehe auch

Verwendung von RLock als Kontextmanager

Empfohlen gegenüber manuellen acquire()- und release()-Aufrufen, wann immer praktikabel.

Wenn mit dem blocking-Argument auf True (Standard) aufgerufen

  • Wenn kein Thread den Lock besitzt, den Lock erwerben und sofort zurückkehren.

  • Wenn ein anderer Thread den Lock besitzt, blockieren, bis wir den Lock erwerben können, oder bis zum timeout, wenn dieser auf einen positiven Float-Wert gesetzt ist.

  • Wenn derselbe Thread den Lock besitzt, den Lock erneut erwerben und sofort zurückkehren. Dies ist der Unterschied zwischen Lock und RLock; Lock behandelt diesen Fall genauso wie den vorherigen, blockiert, bis der Lock erworben werden kann.

Wenn mit dem blocking-Argument auf False aufgerufen

  • Wenn kein Thread den Lock besitzt, den Lock erwerben und sofort zurückkehren.

  • Wenn ein anderer Thread den Lock besitzt, sofort zurückkehren.

  • Wenn derselbe Thread den Lock besitzt, den Lock erneut erwerben und sofort zurückkehren.

In allen Fällen gibt die Methode True zurück, wenn der Thread den Lock erfolgreich erwerben konnte. Wenn der Thread den Lock nicht erwerben konnte (d. h. wenn er nicht blockierend war oder das Timeout erreicht wurde), gibt er False zurück.

Wenn mehrmals aufgerufen, kann das Versäumnis, release() so oft wie nötig aufzurufen, zu Deadlocks führen. Erwägen Sie die Verwendung von RLock als Kontextmanager, anstatt acquire/release direkt aufzurufen.

Geändert in Version 3.2: Der Parameter timeout ist neu.

release()

Gibt einen Lock frei und dekrementiert die Rekursionsebene. Wenn nach der Dekrementierung die Rekursionsebene Null ist, wird der Lock auf ungesperrt zurückgesetzt (nicht von einem Thread besessen) und wenn andere Threads darauf warten, dass der Lock ungesperrt wird, wird genau einer von ihnen fortgesetzt. Wenn nach der Dekrementierung die Rekursionsebene immer noch ungleich Null ist, bleibt der Lock gesperrt und im Besitz des aufrufenden Threads.

Rufen Sie diese Methode nur auf, wenn der aufrufende Thread den Lock besitzt. Ein RuntimeError wird ausgelöst, wenn diese Methode aufgerufen wird, wenn der Lock nicht erworben ist.

Es gibt keinen Rückgabewert.

locked()

Gibt einen booleschen Wert zurück, der angibt, ob dieses Objekt gerade gesperrt ist.

Hinzugefügt in Version 3.14.

Condition-Objekte

Eine Bedingungsvariable ist immer mit einer Art von Lock verbunden; dieser kann übergeben werden oder wird standardmäßig erstellt. Das Übergeben ist nützlich, wenn mehrere Bedingungsvariablen sich denselben Lock teilen müssen. Der Lock ist Teil des Bedingungsobjekts: Sie müssen ihn nicht separat verfolgen.

Eine Bedingungsvariable gehorcht dem Kontextmanagementprotokoll: die Verwendung der with-Anweisung erwirbt den zugehörigen Lock für die Dauer des umschlossenen Blocks. Die Methoden acquire() und release() rufen die entsprechenden Methoden des zugehörigen Locks auf.

Andere Methoden müssen aufgerufen werden, wenn der zugehörige Lock gehalten wird. Die Methode wait() gibt den Lock frei und blockiert dann, bis ein anderer Thread sie durch Aufruf von notify() oder notify_all() aufweckt. Nach dem Aufwachen holt wait() den Lock wieder und kehrt zurück. Es ist auch möglich, eine Zeitüberschreitung anzugeben.

Die Methode notify() weckt einen der Threads auf, die auf die Bedingungsvariable warten, falls welche warten. Die Methode notify_all() weckt alle Threads auf, die auf die Bedingungsvariable warten.

Hinweis: Die Methoden notify() und notify_all() geben den Lock nicht frei; das bedeutet, dass der oder die aufgeweckten Threads nicht sofort aus ihrem wait()-Aufruf zurückkehren, sondern erst, wenn der Thread, der notify() oder notify_all() aufgerufen hat, den Besitz des Locks endgültig aufgibt.

Der typische Programmierstil, der Bedingungsvariablen verwendet, nutzt den Lock, um den Zugriff auf einen gemeinsam genutzten Zustand zu synchronisieren; Threads, die an einer bestimmten Zustandsänderung interessiert sind, rufen wiederholt wait() auf, bis sie den gewünschten Zustand sehen, während Threads, die den Zustand ändern, notify() oder notify_all() aufrufen, wenn sie den Zustand so ändern, dass er für einen der Wartenden ein gewünschter Zustand sein könnte. Zum Beispiel ist der folgende Code eine generische Producer-Consumer-Situation mit unbegrenzter Pufferkapazität

# Consume one item
with cv:
    while not an_item_is_available():
        cv.wait()
    get_an_available_item()

# Produce one item
with cv:
    make_an_item_available()
    cv.notify()

Die while-Schleife, die auf die Bedingung der Anwendung prüft, ist notwendig, da wait() nach einer beliebigen langen Zeit zurückkehren kann und die Bedingung, die den notify()-Aufruf ausgelöst hat, möglicherweise nicht mehr gültig ist. Dies ist inhärent für die Multithreading-Programmierung. Die Methode wait_for() kann verwendet werden, um die Bedingungsprüfung zu automatisieren und erleichtert die Berechnung von Timeouts

# Consume an item
with cv:
    cv.wait_for(an_item_is_available)
    get_an_available_item()

Um zwischen notify() und notify_all() zu wählen, überlegen Sie, ob eine Zustandsänderung nur für einen oder mehrere wartende Threads interessant sein kann. Zum Beispiel muss im typischen Producer-Consumer-Fall das Hinzufügen eines Elements zum Puffer nur einen Consumer-Thread aufwecken.

class threading.Condition(lock=None)

Diese Klasse implementiert Bedingungsvariablenobjekte. Eine Bedingungsvariable ermöglicht es einem oder mehreren Threads, zu warten, bis sie von einem anderen Thread benachrichtigt werden.

Wenn das lock Argument gegeben und nicht None ist, muss es ein Lock- oder RLock-Objekt sein und wird als zugrunde liegendes Sperrobjekt verwendet. Andernfalls wird ein neues RLock-Objekt erstellt und als zugrunde liegendes Sperrobjekt verwendet.

Geändert in Version 3.3: Von einer Factory-Funktion zu einer Klasse geändert.

acquire(*args)

Erfasst die zugrunde liegende Sperre. Diese Methode ruft die entsprechende Methode des zugrunde liegenden Sperrobjekts auf; der Rückgabewert ist das, was diese Methode zurückgibt.

release()

Gibt die zugrunde liegende Sperre frei. Diese Methode ruft die entsprechende Methode des zugrunde liegenden Sperrobjekts auf; es gibt keinen Rückgabewert.

locked()

Gibt einen booleschen Wert zurück, der angibt, ob dieses Objekt gerade gesperrt ist.

Hinzugefügt in Version 3.14.

wait(timeout=None)

Wartet bis zur Benachrichtigung oder bis eine Zeitüberschreitung eintritt. Wenn der aufrufende Thread die Sperre nicht erfasst hat, wenn diese Methode aufgerufen wird, wird eine RuntimeError ausgelöst.

Diese Methode gibt die zugrunde liegende Sperre frei und blockiert dann, bis sie durch einen Aufruf von notify() oder notify_all() für dieselbe Bedingungsvariable in einem anderen Thread geweckt wird oder bis die optionale Zeitüberschreitung eintritt. Nach dem Erwachen oder Ablauf der Zeitüberschreitung wird die Sperre erneut erfasst und zurückgekehrt.

Wenn das timeout Argument vorhanden und nicht None ist, sollte es eine Gleitkommazahl sein, die eine Zeitüberschreitung für die Operation in Sekunden (oder Bruchteilen davon) angibt.

Wenn die zugrunde liegende Sperre ein RLock ist, wird sie nicht mit ihrer release()-Methode freigegeben, da dies die Sperre möglicherweise nicht tatsächlich aufhebt, wenn sie mehrmals rekursiv erfasst wurde. Stattdessen wird eine interne Schnittstelle der RLock-Klasse verwendet, die sie tatsächlich aufhebt, auch wenn sie mehrfach rekursiv erfasst wurde. Eine weitere interne Schnittstelle wird dann verwendet, um die Rekursionsebene wiederherzustellen, wenn die Sperre erneut erfasst wird.

Der Rückgabewert ist True, es sei denn, eine angegebene timeout ist abgelaufen, in diesem Fall ist er False.

Geändert in Version 3.2: Zuvor gab die Methode immer None zurück.

wait_for(predicate, timeout=None)

Wartet, bis eine Bedingung zu wahr ausgewertet wird. predicate sollte ein aufrufbares Objekt sein, dessen Ergebnis als boolescher Wert interpretiert wird. Eine timeout kann angegeben werden, um die maximale Wartezeit festzulegen.

Diese Hilfsmethode kann wiederholt wait() aufrufen, bis das Prädikat erfüllt ist oder eine Zeitüberschreitung eintritt. Der Rückgabewert ist der letzte Rückgabewert des Prädikats und wird zu False ausgewertet, wenn die Methode abgelaufen ist.

Wenn die Zeitüberschreitungsfunktion ignoriert wird, ist der Aufruf dieser Methode ungefähr gleichwertig mit:

while not predicate():
    cv.wait()

Daher gelten dieselben Regeln wie bei wait(): Die Sperre muss beim Aufruf gehalten werden und wird bei Rückgabe neu erfasst. Das Prädikat wird mit gehaltener Sperre ausgewertet.

Hinzugefügt in Version 3.2.

notify(n=1)

Weckt standardmäßig einen Thread, der auf dieser Bedingung wartet, falls vorhanden. Wenn der aufrufende Thread die Sperre nicht erfasst hat, wenn diese Methode aufgerufen wird, wird eine RuntimeError ausgelöst.

Diese Methode weckt höchstens n der auf die Bedingungsvariable wartenden Threads; sie ist eine No-Op, wenn keine Threads warten.

Die aktuelle Implementierung weckt genau n Threads, wenn mindestens n Threads warten. Es ist jedoch nicht sicher, sich auf dieses Verhalten zu verlassen. Eine zukünftige, optimierte Implementierung kann gelegentlich mehr als n Threads wecken.

Hinweis: Ein gewecker Thread kehrt tatsächlich erst aus seinem wait()-Aufruf zurück, wenn er die Sperre erneut erfassen kann. Da notify() die Sperre nicht freigibt, sollte ihr Aufrufer dies tun.

notify_all()

Weckt alle Threads, die auf dieser Bedingung warten. Diese Methode verhält sich wie notify(), weckt aber alle wartenden Threads anstelle von einem. Wenn der aufrufende Thread die Sperre nicht erfasst hat, wenn diese Methode aufgerufen wird, wird eine RuntimeError ausgelöst.

Die Methode notifyAll ist ein veralteter Alias für diese Methode.

Semaphore-Objekte

Dies ist einer der ältesten Synchronisationsprimitiven in der Geschichte der Informatik, erfunden vom frühen niederländischen Informatiker Edsger W. Dijkstra (er verwendete die Namen P() und V() anstelle von acquire() und release()).

Ein Semaphor verwaltet einen internen Zähler, der bei jedem acquire()-Aufruf dekrementiert und bei jedem release()-Aufruf inkrementiert wird. Der Zähler kann niemals unter Null fallen; wenn acquire() feststellt, dass er Null ist, blockiert er und wartet, bis ein anderer Thread release() aufruft.

Semaphoren unterstützen auch das Kontextmanagement-Protokoll.

class threading.Semaphore(value=1)

Diese Klasse implementiert Semaphorobjekte. Ein Semaphor verwaltet einen atomaren Zähler, der die Anzahl der release()-Aufrufe abzüglich der Anzahl der acquire()-Aufrufe, plus einem Anfangswert, darstellt. Die acquire()-Methode blockiert, falls erforderlich, bis sie zurückkehren kann, ohne den Zähler negativ zu machen. Wenn value nicht angegeben wird, ist der Standardwert 1.

Das optionale Argument gibt den anfänglichen value für den internen Zähler an; standardmäßig ist dies 1. Wenn der angegebene value kleiner als 0 ist, wird ValueError ausgelöst.

Geändert in Version 3.3: Von einer Factory-Funktion zu einer Klasse geändert.

acquire(blocking=True, timeout=None)

Erfasst ein Semaphor.

Wenn ohne Argumente aufgerufen:

  • Wenn der interne Zähler bei Eintritt größer als Null ist, dekrementieren Sie ihn um eins und geben Sie sofort True zurück.

  • Wenn der interne Zähler bei Eintritt Null ist, blockieren Sie, bis Sie durch einen Aufruf von release() geweckt werden. Sobald Sie geweckt werden (und der Zähler größer als 0 ist), dekrementieren Sie den Zähler um eins und geben Sie True zurück. Genau ein Thread wird durch jeden Aufruf von release() geweckt. Die Reihenfolge, in der Threads geweckt werden, sollte nicht berücksichtigt werden.

Wenn blocking auf False gesetzt ist, blockieren Sie nicht. Wenn ein Aufruf ohne Argument blockieren würde, geben Sie sofort False zurück; andernfalls tun Sie dasselbe wie bei einem Aufruf ohne Argumente und geben Sie True zurück.

Wenn mit einem timeout ungleich None aufgerufen, wird bis zu timeout Sekunden lang blockiert. Wenn die Erfassung in diesem Intervall nicht erfolgreich ist, geben Sie False zurück. Geben Sie andernfalls True zurück.

Geändert in Version 3.2: Der Parameter timeout ist neu.

release(n=1)

Gibt ein Semaphor frei und inkrementiert den internen Zähler um n. Wenn er bei Eintritt Null war und andere Threads darauf warten, dass er wieder größer als Null wird, werden n dieser Threads geweckt.

Geändert in Version 3.9: Der Parameter n wurde hinzugefügt, um mehrere wartende Threads gleichzeitig zu wecken.

class threading.BoundedSemaphore(value=1)

Klasse zur Implementierung von beschränkten Semaphorobjekten. Ein beschränktes Semaphor prüft, ob sein aktueller Wert seinen Anfangswert nicht überschreitet. Wenn dies der Fall ist, wird ValueError ausgelöst. In den meisten Situationen werden Semaphoren verwendet, um Ressourcen mit begrenzter Kapazität zu schützen. Wenn das Semaphor zu oft freigegeben wird, ist dies ein Zeichen für einen Fehler. Wenn value nicht angegeben wird, ist der Standardwert 1.

Geändert in Version 3.3: Von einer Factory-Funktion zu einer Klasse geändert.

Semaphore Beispiel

Semaphoren werden oft verwendet, um Ressourcen mit begrenzter Kapazität zu schützen, z. B. einen Datenbankserver. In jeder Situation, in der die Größe der Ressource fest ist, sollten Sie ein beschränktes Semaphor verwenden. Bevor Sie Worker-Threads starten, würde Ihr Haupt-Thread das Semaphor initialisieren

maxconnections = 5
# ...
pool_sema = BoundedSemaphore(value=maxconnections)

Sobald sie gestartet sind, rufen die Worker-Threads die `acquire`- und `release`-Methoden des Semaphors auf, wenn sie sich mit dem Server verbinden müssen

with pool_sema:
    conn = connectdb()
    try:
        # ... use connection ...
    finally:
        conn.close()

Die Verwendung eines beschränkten Semaphors reduziert die Wahrscheinlichkeit, dass ein Programmierfehler, der dazu führt, dass das Semaphor mehr als einmal freigegeben wird, unentdeckt bleibt.

Ereignisobjekte

Dies ist einer der einfachsten Mechanismen für die Kommunikation zwischen Threads: Ein Thread signalisiert ein Ereignis und andere Threads warten darauf.

Ein Ereignisobjekt verwaltet ein internes Flag, das mit der Methode set() auf true gesetzt und mit der Methode clear() auf false zurückgesetzt werden kann. Die Methode wait() blockiert, bis das Flag true ist.

class threading.Event

Klasse zur Implementierung von Ereignisobjekten. Ein Ereignis verwaltet ein Flag, das mit der Methode set() auf true gesetzt und mit der Methode clear() auf false zurückgesetzt werden kann. Die Methode wait() blockiert, bis das Flag true ist. Das Flag ist anfänglich false.

Geändert in Version 3.3: Von einer Factory-Funktion zu einer Klasse geändert.

is_set()

Gibt True genau dann zurück, wenn das interne Flag true ist.

Die Methode isSet ist ein veralteter Alias für diese Methode.

set()

Setzt das interne Flag auf true. Alle wartenden Threads werden geweckt. Threads, die wait() aufrufen, während das Flag true ist, werden überhaupt nicht blockiert.

clear()

Setzt das interne Flag auf false zurück. Anschließend blockieren Threads, die wait() aufrufen, bis set() aufgerufen wird, um das interne Flag wieder auf true zu setzen.

wait(timeout=None)

Blockiert, solange das interne Flag false ist und die Zeitüberschreitung, falls gegeben, nicht abgelaufen ist. Der Rückgabewert gibt den Grund an, warum diese blockierende Methode zurückgegeben hat: True, wenn die Rückgabe erfolgt, weil das interne Flag auf true gesetzt ist, oder False, wenn eine Zeitüberschreitung angegeben ist und das interne Flag nicht innerhalb der angegebenen Wartezeit auf true gesetzt wurde.

Wenn das timeout Argument vorhanden und nicht None ist, sollte es eine Gleitkommazahl sein, die eine Zeitüberschreitung für die Operation in Sekunden oder Bruchteilen davon angibt.

Geändert in Version 3.1: Zuvor gab die Methode immer None zurück.

Timer-Objekte

Diese Klasse stellt eine Aktion dar, die nur nach einer bestimmten Zeit ausgeführt werden soll – ein Timer. Timer ist eine Unterklasse von Thread und fungiert somit auch als Beispiel für die Erstellung benutzerdefinierter Threads.

Timer werden, wie Threads, durch Aufrufen ihrer Timer.start-Methode gestartet. Der Timer kann (bevor seine Aktion begonnen hat) durch Aufrufen der cancel()-Methode gestoppt werden. Das Intervall, das der Timer vor der Ausführung seiner Aktion wartet, ist möglicherweise nicht genau dasselbe wie das vom Benutzer angegebene Intervall.

Zum Beispiel

def hello():
    print("hello, world")

t = Timer(30.0, hello)
t.start()  # after 30 seconds, "hello, world" will be printed
class threading.Timer(interval, function, args=None, kwargs=None)

Erstellt einen Timer, der function mit den Argumenten args und den Schlüsselwortargumenten kwargs nach Ablauf von interval Sekunden ausführt. Wenn args None ist (Standard), wird eine leere Liste verwendet. Wenn kwargs None ist (Standard), wird ein leeres Wörterbuch verwendet.

Geändert in Version 3.3: Von einer Factory-Funktion zu einer Klasse geändert.

cancel()

Stoppt den Timer und bricht die Ausführung der Timer-Aktion ab. Dies funktioniert nur, wenn sich der Timer noch im Wartezustand befindet.

Barriere-Objekte

Hinzugefügt in Version 3.2.

Diese Klasse bietet ein einfaches Synchronisationsprimitiv für eine feste Anzahl von Threads, die aufeinander warten müssen. Jeder der Threads versucht, die Barriere zu passieren, indem er die Methode wait() aufruft und blockiert, bis alle Threads ihre wait()-Aufrufe getätigt haben. Zu diesem Zeitpunkt werden die Threads gleichzeitig freigegeben.

Die Barriere kann beliebig oft für dieselbe Anzahl von Threads wiederverwendet werden.

Als Beispiel hier eine einfache Möglichkeit, einen Client- und einen Server-Thread zu synchronisieren

b = Barrier(2, timeout=5)

def server():
    start_server()
    b.wait()
    while True:
        connection = accept_connection()
        process_server_connection(connection)

def client():
    b.wait()
    while True:
        connection = make_connection()
        process_client_connection(connection)
class threading.Barrier(parties, action=None, timeout=None)

Erstellt ein Barriereobjekt für parties Anzahl von Threads. Eine action, wenn angegeben, ist ein aufrufbares Objekt, das von einem der Threads aufgerufen wird, wenn sie freigegeben werden. timeout ist der Standardwert für die Zeitüberschreitung, wenn keiner für die wait()-Methode angegeben ist.

wait(timeout=None)

Übergibt die Barriere. Wenn alle Threads, die zur Barriere gehören, diese Funktion aufgerufen haben, werden sie gleichzeitig freigegeben. Wenn ein timeout angegeben wird, wird dieser gegenüber jedem, der dem Konstruktor der Klasse übergeben wurde, bevorzugt.

Der Rückgabewert ist eine Ganzzahl im Bereich von 0 bis parties – 1, die für jeden Thread unterschiedlich ist. Dies kann verwendet werden, um einen Thread zur Durchführung bestimmter Sonderaufgaben auszuwählen, z. B.

i = barrier.wait()
if i == 0:
    # Only one thread needs to print this
    print("passed the barrier")

Wenn im Konstruktor eine action angegeben wurde, wird einer der Threads diese vor der Freigabe aufgerufen haben. Wenn dieser Aufruf einen Fehler auslöst, wird die Barriere in den defekten Zustand versetzt.

Wenn der Aufruf abläuft, wird die Barriere in den defekten Zustand versetzt.

Diese Methode kann eine BrokenBarrierError-Ausnahme auslösen, wenn die Barriere zurückgesetzt oder defekt ist, während ein Thread wartet.

reset()

Setzt die Barriere in den Standardzustand (leer) zurück. Alle darauf wartenden Threads erhalten die Ausnahme BrokenBarrierError.

Beachten Sie, dass die Verwendung dieser Funktion eine externe Synchronisation erfordern kann, wenn andere Threads vorhanden sind, deren Zustand unbekannt ist. Wenn eine Barriere defekt ist, ist es möglicherweise besser, sie einfach zu belassen und eine neue zu erstellen.

abort()

Versetzt die Barriere in einen defekten Zustand. Dies führt dazu, dass alle aktiven oder zukünftigen Aufrufe von wait() mit BrokenBarrierError fehlschlagen. Verwenden Sie dies beispielsweise, wenn einer der Threads abbrach muss, um eine Blockade der Anwendung zu vermeiden.

Es kann ratsamer sein, die Barriere einfach mit einem sinnvollen timeout-Wert zu erstellen, um automatisch zu verhindern, dass einer der Threads außer Kontrolle gerät.

parties

Die Anzahl der Threads, die die Barriere passieren müssen.

n_waiting

Die Anzahl der Threads, die derzeit auf die Barriere warten.

broken

Ein boolescher Wert, der True ist, wenn die Barriere im defekten Zustand ist.

exception threading.BrokenBarrierError

Diese Ausnahme, eine Unterklasse von RuntimeError, wird ausgelöst, wenn das Barrier-Objekt zurückgesetzt oder defekt ist.

Verwendung von Sperren, Bedingungen und Semaphoren in der with-Anweisung

Alle von diesem Modul bereitgestellten Objekte mit `acquire`- und `release`-Methoden können als Kontextmanager für eine with-Anweisung verwendet werden. Die `acquire`-Methode wird aufgerufen, wenn der Block betreten wird, und `release` wird aufgerufen, wenn der Block verlassen wird. Daher ist der folgende Ausschnitt

with some_lock:
    # do something...

gleichbedeutend ist mit

some_lock.acquire()
try:
    # do something...
finally:
    some_lock.release()

Derzeit können Lock-, RLock-, Condition-, Semaphore- und BoundedSemaphore-Objekte als with-Statement-Kontextmanager verwendet werden.