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 vonenumerate()zurückgegeben wird.Die Funktion
activeCountist 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 Modulthreadingerstellt wurde, wird ein Dummy-Thread-Objekt mit eingeschränkter Funktionalität zurückgegeben.Die Funktion
currentThreadist 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
Nonesein.exc_traceback: Ausnahme-Traceback, kann
Nonesein.thread: Thread, der die Ausnahme ausgelöst hat, kann
Nonesein.
Wenn exc_type
SystemExitist, wird die Ausnahme stillschweigend ignoriert. Andernfalls wird die Ausnahme aufsys.stderrausgegeben.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 vonThread.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 voncurrent_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
threadinggestartet wurden. func wird für jeden Thread ansys.settrace()übergeben, bevor dessenrun()-Methode aufgerufen wird.
- threading.settrace_all_threads(func)¶
Setzt eine Trace-Funktion für alle Threads, die aus dem Modul
threadinggestartet wurden, sowie für alle aktuell ausgeführten Python-Threads.func wird für jeden Thread an
sys.settrace()übergeben, bevor dessenrun()-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
threadinggestartet wurden. func wird für jeden Thread ansys.setprofile()übergeben, bevor dessenrun()-Methode aufgerufen wird.
- threading.setprofile_all_threads(func)¶
Setzt eine Profiler-Funktion für alle Threads, die aus dem Modul
threadinggestartet wurden, sowie für alle aktuell ausgeführten Python-Threads.func wird für jeden Thread an
sys.setprofile()übergeben, bevor dessenrun()-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
RuntimeErrorausgelöst. Wenn die angegebene Stackgröße ungültig ist, wird einValueErrorausgelö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 einenOverflowErroraus.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
Nonesein; reserviert für zukünftige Erweiterungen, wenn eine KlasseThreadGroupimplementiert wird.target ist das aufrufbare Objekt, das von der Methode
run()aufgerufen wird. StandardmäßigNone, 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
Noneist, legt es explizit fest, ob der Thread ein Daemon-Thread ist. WennNone(der Standardwert), wird die Daemon-Eigenschaft vom aktuellen Thread übernommen.context ist der
Context-Wert, der beim Starten des Threads verwendet wird. Der Standardwert istNone, was bedeutet, dass das Flagsys.flags.thread_inherit_contextdas Verhalten steuert. Wenn das Flag wahr ist, starten Threads mit einer Kopie des Kontexts des Aufrufers vonstart(). Wenn falsch, starten sie mit einem leeren Kontext. Um explizit mit einem leeren Kontext zu starten, übergeben Sie eine neue Instanz vonContext(). Um explizit mit einer Kopie des aktuellen Kontexts zu starten, übergeben Sie den Wert voncopy_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
RuntimeErroraus, wenn sie mehr als einmal für dasselbe Thread-Objekt aufgerufen wird.Wenn unterstützt, wird der Betriebssystem-Thread-Name auf
threading.Thread.namegesetzt. 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
Noneist, sollte es eine Gleitkommazahl sein, die eine Zeitüberschreitung für die Operation in Sekunden (oder Bruchteilen davon) angibt. Dajoin()immerNonezurückgibt, müssen Sieis_alive()nach dem Aufruf vonjoin()aufrufen, um zu entscheiden, ob eine Zeitüberschreitung stattgefunden hat – wenn der Thread noch lebt, ist der Aufruf vonjoin()abgelaufen.Wenn das timeout-Argument nicht vorhanden oder
Noneist, wird die Operation blockiert, bis der Thread beendet ist.Ein Thread kann mehrmals gejoined werden.
join()löst einenRuntimeErroraus, 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()einenPythonFinalizationErroraus.Geändert in Version 3.14: Kann
PythonFinalizationErrorauslö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 Funktionget_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 oderNone, wenn der Thread nicht gestartet wurde. Siehe die Funktionget_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
Truezurück, unmittelbar bevor die Methoderun()beginnt, bis unmittelbar nach Beendigung der Methoderun(). Die Modul-Funktionenumerate()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, bevorstart()aufgerufen wird, andernfalls wird einRuntimeErrorausgelö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 aufdaemon=Falsegesetzt.Das gesamte Python-Programm wird beendet, wenn keine aktiven Nicht-Daemon-Threads mehr übrig sind.
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:
Lockist jetzt eine Klasse. In früheren Pythons warLockeine 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 undTruezurückgibt.Wenn mit dem blocking-Argument auf
Falseaufgerufen, blockiert nicht. Wenn ein Aufruf mit blocking aufTrueblockieren würde, kehrt er sofortFalsezurück; andernfalls wird der Lock auf gesperrt gesetzt undTruezurü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
-1gibt eine unbegrenzte Wartezeit an. Es ist verboten, ein timeout anzugeben, wenn blocking aufFalsegesetzt 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
RuntimeErrorausgelöst.Es gibt keinen Rückgabewert.
- locked()¶
Gibt
Truezurü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
RLocktatsä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()- undrelease()-Aufrufen, wann immer praktikabel.
Wenn mit dem blocking-Argument auf
True(Standard) aufgerufenWenn 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
LockundRLock;Lockbehandelt diesen Fall genauso wie den vorherigen, blockiert, bis der Lock erworben werden kann.
Wenn mit dem blocking-Argument auf
FalseaufgerufenWenn 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
Truezurü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 erFalsezurück.Wenn mehrmals aufgerufen, kann das Versäumnis,
release()so oft wie nötig aufzurufen, zu Deadlocks führen. Erwägen Sie die Verwendung vonRLockals 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
RuntimeErrorwird 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
Noneist, muss es einLock- oderRLock-Objekt sein und wird als zugrunde liegendes Sperrobjekt verwendet. Andernfalls wird ein neuesRLock-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
RuntimeErrorausgelöst.Diese Methode gibt die zugrunde liegende Sperre frei und blockiert dann, bis sie durch einen Aufruf von
notify()odernotify_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
Noneist, 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
RLockist, wird sie nicht mit ihrerrelease()-Methode freigegeben, da dies die Sperre möglicherweise nicht tatsächlich aufhebt, wenn sie mehrmals rekursiv erfasst wurde. Stattdessen wird eine interne Schnittstelle derRLock-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 erFalse.Geändert in Version 3.2: Zuvor gab die Methode immer
Nonezurü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 zuFalseausgewertet, 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
RuntimeErrorausgelö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. Danotify()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 eineRuntimeErrorausgelöst.Die Methode
notifyAllist 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 deracquire()-Aufrufe, plus einem Anfangswert, darstellt. Dieacquire()-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, wirdValueErrorausgelö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
Truezurü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 SieTruezurück. Genau ein Thread wird durch jeden Aufruf vonrelease()geweckt. Die Reihenfolge, in der Threads geweckt werden, sollte nicht berücksichtigt werden.
Wenn blocking auf
Falsegesetzt ist, blockieren Sie nicht. Wenn ein Aufruf ohne Argument blockieren würde, geben Sie sofortFalsezurück; andernfalls tun Sie dasselbe wie bei einem Aufruf ohne Argumente und geben SieTruezurück.Wenn mit einem timeout ungleich
Noneaufgerufen, wird bis zu timeout Sekunden lang blockiert. Wenn die Erfassung in diesem Intervall nicht erfolgreich ist, geben SieFalsezurück. Geben Sie andernfallsTruezurü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
ValueErrorausgelö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 Methodeclear()auf false zurückgesetzt werden kann. Die Methodewait()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
Truegenau dann zurück, wenn das interne Flag true ist.Die Methode
isSetist 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, bisset()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, oderFalse, 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
Noneist, 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
Nonezurü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
Noneist (Standard), wird eine leere Liste verwendet. Wenn kwargsNoneist (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()mitBrokenBarrierErrorfehlschlagen. 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
Trueist, wenn die Barriere im defekten Zustand ist.
- exception threading.BrokenBarrierError¶
Diese Ausnahme, eine Unterklasse von
RuntimeError, wird ausgelöst, wenn dasBarrier-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.