Regel
Sicherstellen, dass thread-safe Zugriff auf gemeinsamen Zustand.
Gemeinsam genutzte veränderbar Zustand Zugriff auf durch mehrere Threads
ohne Synchronisierung verursacht Rennen Bedingungen und Laufzeit Fehler.
Unterstützte Sprachen: Python, Java, C#Einführung
Wenn mehrere Threads ohne Synchronisierung auf gemeinsam genutzte Variablen zugreifen und diese ändern, treten Race Conditions auf. Der endgültige Wert hängt vom unvorhersehbaren Ausführungszeitpunkt der Threads ab, was zu Datenbeschädigungen, falschen Berechnungen oder Laufzeitfehlern führt. Ein Zähler, der von mehreren Threads ohne Sperre inkrementiert wird, verpasst Aktualisierungen, wenn Threads veraltete Werte lesen, sie inkrementieren und widersprüchliche Ergebnisse zurückschreiben.
Warum das wichtig ist
Datenbeschädigung und falsche Ergebnisse: Race Conditions verursachen eine stille Datenkorruption, bei der Werte inkonsistent oder falsch werden. Kontostände können falsch sein, Bestandszahlen können negativ sein, oder aggregierte Statistiken können verfälscht werden. Diese Fehler sind schwer zu reproduzieren, da sie vom exakten Thread-Timing abhängen.
Systeminstabilität: Ein unsynchronisierter Zugriff auf einen gemeinsamen Zustand kann Anwendungen zum Absturz bringen. Ein Thread kann eine Datenstruktur ändern, während ein anderer sie liest, was zu Ausnahmen wie Nullzeigerfehlern oder Indexüberschreitungen führt. In der Produktion äußert sich dies in zeitweiligen Abstürzen unter Last.
Komplexität bei der Fehlersuche: Race Conditions sind notorisch schwierig zu debuggen, da sie nicht deterministisch sind. In Single-Thread-Tests oder Umgebungen mit geringer Last tritt der Fehler möglicherweise nicht auf. Die Reproduktion erfordert ein spezielles Thread-Interleaving, das schwer zu erzwingen ist, so dass die Probleme zufällig auftreten und wieder verschwinden.
Code-Beispiele
❌ Nicht konform:
class BankAccount:
def __init__(self):
self.balance = 0
def deposit(self, amount):
current = self.balance
#
time.sleep(0.001) # Simuliert die Verarbeitungszeit
self.balance = current + amount
def withdraw(self, amount):
if self.balance >= amount:
current = self.balance
time.sleep(0.001)
self.balance = current - amount
return True
return False
Warum das falsch ist: Mehrere Threads, die gleichzeitig deposit() oder withdraw() aufrufen, schaffen Wettlaufbedingungen. Zwei Threads, die jeweils $100 einzahlen, könnten beide den Saldo als $0 lesen und dann beide $100 schreiben, was zu einem Endsaldo von $100 statt $200 führt.
✅ Konform:
Threadingimportieren
class BankAccount:
def __init__(self):
self.__balance = 0
self.__lock = threading.Lock()
@property
def balance(self):
with self.__lock:
return self.__balance
def deposit(self, amount):
with self.__lock:
current = self.__balance
time.sleep(0.001)
self.__balance = aktuell + Betrag
def withdraw(self, amount):
with self.__lock:
if self.__balance >= amount:
current = self.__balance
time.sleep(0.001)
self.__balance = current - amount
return True
return False
Warum das wichtig ist: Die threading.Lock() stellt sicher, dass jeweils nur ein Thread auf das Gleichgewicht zugreift. Wenn ein Thread die Sperre hält, warten die anderen, um gleichzeitige Änderungen zu verhindern. Privat __balance mit schreibgeschütztem @Eigentum verhindert, dass ein externer Code den Sperrschutz umgeht.
Schlussfolgerung
Schützen Sie alle gemeinsam genutzten veränderbaren Zustände mit geeigneten Synchronisationsprimitiven wie Sperren, Semaphoren oder atomaren Operationen. Bevorzugen Sie unveränderliche Datenstrukturen oder thread-lokale Speicherung, wenn möglich. Wenn Synchronisierung notwendig ist, minimieren Sie kritische Abschnitte, um Konflikte zu reduzieren und die Leistung zu verbessern.
.avif)
