Thread-Sperre in Python

Muhammad Maisam Abbas 23 Januar 2022
  1. Racebedingung in Python
  2. Thread-Sperre in Python
  3. Thread-Sperre mit with lock: in Python
Thread-Sperre in Python

In diesem Tutorial werden verschiedene Methoden zur Verwendung einer Threadsperre in Python erläutert.

Racebedingung in Python

Eine Racebedingung ist ein Problem, das auftritt, wenn mehrere Threads versuchen, dieselbe gemeinsam genutzte Variable zu ändern. Alle Threads lesen gleichzeitig denselben Wert aus der gemeinsamen Variablen. Dann versuchen alle Threads, den Wert der gemeinsamen Variablen zu ändern. Die Variable speichert jedoch nur den Wert des letzten Threads, da sie den vom vorherigen Thread geschriebenen Wert überschreibt. In diesem Sinne gibt es einen Wettlauf zwischen allen Threads, welcher am Ende den Wert der Variablen ändert. Dieses Phänomen wird mit einem Beispiel im folgenden Code demonstriert.

from threading import Thread

counter = 0


def increase(by):
    global counter
    local_counter = counter
    local_counter += by
    counter = local_counter
    print(f"counter={counter}")


t1 = Thread(target=increase, args=(10,))
t2 = Thread(target=increase, args=(20,))

t1.start()
t2.start()

t1.join()
t2.join()

print(f"The final counter is {counter}")

Ausgabe:

counter=10
counter=20
The final counter is 20

Wir haben eine globale gemeinsame Variable counter = 0 und zwei Threads t1 und t2. Der Thread t1 versucht, den Wert von counter um 10 zu erhöhen und der Thread t2 versucht, den Wert von counter um 20 zu erhöhen. Im obigen Code führen wir beide Threads gleichzeitig aus und versuchen, den Wert zu ändern von Zähler. Nach der obigen Logik sollte der Endwert von counter den Wert 30 haben. Aber wegen der Race-Condition ist der counter entweder 10 oder 20.

Thread-Sperre in Python

Die Thread-Sperre wird verwendet, um die Race-Bedingung zu verhindern. Die Thread-Sperre sperrt den Zugriff auf eine gemeinsam genutzte Variable, wenn sie von einem Thread verwendet wird, sodass kein anderer Thread darauf zugreifen kann, und entfernt dann die Sperre, wenn der Thread die gemeinsam genutzte Variable nicht verwendet, sodass die Variable anderen Threads zur Verarbeitung zur Verfügung steht. Die Lock-Klasse innerhalb des Threading-Moduls wird verwendet, um eine Thread-Sperre in Python zu erstellen. Die Methode acquire() wird verwendet, um den Zugriff auf eine gemeinsame Variable zu sperren, und die Methode release() wird verwendet, um die Sperre aufzuheben. Die Methode release() löst eine RuntimeError-Ausnahme aus, wenn sie für eine entsperrte Sperre verwendet wird.

from threading import Thread, Lock

counter = 0


def increase(by, lock):
    global counter

    lock.acquire()

    local_counter = counter
    local_counter += by
    counter = local_counter
    print(f"counter={counter}")

    lock.release()


lock = Lock()

t1 = Thread(target=increase, args=(10, lock))
t2 = Thread(target=increase, args=(20, lock))

t1.start()
t2.start()

t1.join()
t2.join()

print(f"The final counter is {counter}")

Ausgabe:

counter=10
counter=30
The final counter is 30

Wir haben eine global geteilte Variable counter=0 und zwei Threads t1 und t2 erstellt. Beide Threads zielen auf dieselbe Funktion increase() ab. Die Funktion increase(by, lock) benötigt zwei Parameter. Der erste Parameter ist der Betrag, um den counter erhöht wird, und der zweite Parameter ist eine Instanz der Lock-Klasse. Zusätzlich zu den vorherigen Deklarationen haben wir auch eine Instanz lock der Lock-Klasse innerhalb des threading-Moduls von Python erstellt. Dieser Parameter lock in der Funktion increase(by, lock) sperrt den Zugriff auf die Variable counter mit der Funktion lock.acquire(), während sie von einem beliebigen Thread verändert wird, und entsperrt die Sperre mit lock.release()-Funktion, wenn ein Thread die Variable counter modifiziert hat. Der Thread t1 erhöht den Wert von counter um 10 und der Thread t2 erhöht den Wert von counter um 20.

Aufgrund der Thread-Sperre tritt die Race Condition nicht auf und der Endwert von counter ist 30.

Thread-Sperre mit with lock: in Python

Das Problem bei der vorherigen Methode besteht darin, dass wir jede gesperrte Variable sorgfältig entsperren müssen, wenn ein Thread die Verarbeitung abgeschlossen hat. Wenn es nicht richtig gemacht wird, wird nur der erste Thread auf unsere Shared Variable zugreifen, und kein anderer Thread erhält Zugriff auf die Shared Variable. Dieses Problem kann durch die Verwendung der Kontextverwaltung vermieden werden. Wir können with lock: verwenden und all unseren kritischen Code in diesem Block platzieren. Dies ist eine viel einfachere Möglichkeit, Rennbedingungen zu verhindern. Der folgende Codeausschnitt zeigt die Verwendung von with lock:, um die Race-Condition in Python zu verhindern.

from threading import Thread, Lock

counter = 0


def increase(by, lock):
    global counter

    with lock:
        local_counter = counter
        local_counter += by
        counter = local_counter
    print(f"counter={counter}")


lock = Lock()

t1 = Thread(target=increase, args=(10, lock))
t2 = Thread(target=increase, args=(20, lock))

t1.start()
t2.start()

t1.join()
t2.join()

print(f"The final counter is {counter}")

Ausgabe:

counter=10
counter=30
The final counter is 30

Wir haben unseren Code zum Inkrementieren von counter im with lock:-Block platziert. Der Thread t1 erhöht den Wert von counter um 10 und der Thread t2 erhöht den Wert von counter um 20. Die Race-Bedingung tritt nicht auf und der Endwert von counter ist 30. Außerdem , Wir brauchen uns keine Sorgen um das Entsperren der Schraubensicherung zu machen.

Beide Methoden machen ihren Job perfekt, d.h. beide Methoden verhindern das Auftreten der Race Condition, aber die zweite Methode ist der ersten weit überlegen, da sie uns die Kopfschmerzen beim Sperren und Entsperren von Thread-Locks erspart. Es ist auch viel sauberer zu schreiben und leichter zu lesen als die erste Methode.

Muhammad Maisam Abbas avatar Muhammad Maisam Abbas avatar

Maisam is a highly skilled and motivated Data Scientist. He has over 4 years of experience with Python programming language. He loves solving complex problems and sharing his results on the internet.

LinkedIn

Verwandter Artikel - Python Thread