Verrouillage de thread en Python

Muhammad Maisam Abbas 23 janvier 2022
  1. Condition de course en Python
  2. Verrouillage de thread en Python
  3. Thread Lock Utilisation de with lock: en Python
Verrouillage de thread en Python

Ce didacticiel abordera différentes méthodes pour utiliser un verrou de thread en Python.

Condition de course en Python

Une condition de concurrence critique est un problème qui se produit lorsque plusieurs threads tentent de modifier la même variable partagée. Tous les threads lisent la même valeur à partir de la variable partagée en même temps. Ensuite, tous les threads essaient de modifier la valeur de la variable partagée. Mais, la variable ne finit par stocker que la valeur du dernier thread car elle écrase la valeur écrite par le thread précédent. En ce sens, il y a une course entre tous les threads pour voir lequel modifie la valeur de la variable à la fin. Ce phénomène est illustré par un exemple dans le code suivant.

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}")

Production :

counter=10
counter=20
The final counter is 20

Nous avons une variable globale partagée counter = 0 et deux threads t1 et t2. Le thread t1 essaie d’incrémenter la valeur de counter de 10 et le thread t2 essaie d’incrémenter la valeur de counter de 20. Dans le code ci-dessus, nous exécutons les deux threads simultanément et essayons de modifier la valeur de counter. Selon la logique ci-dessus, la valeur finale de counter devrait avoir la valeur 30. Mais, en raison de la condition de concurrence, le counter est soit 10, soit 20.

Verrouillage de thread en Python

Le verrou de filetage est utilisé pour empêcher la condition de concurrence. Le verrou de thread verrouille l’accès à une variable partagée lorsqu’elle est utilisée par un thread afin qu’aucun autre thread ne puisse y accéder, puis supprime le verrou lorsque le thread n’utilise pas la variable partagée afin que la variable soit disponible pour d’autres threads pour le traitement. La classe Lock à l’intérieur du module de threading est utilisée pour créer un verrou de thread en Python. La méthode acquire() est utilisée pour verrouiller l’accès à une variable partagée, et la méthode release() est utilisée pour déverrouiller le verrou. La méthode release() lève une exception RuntimeError si elle est utilisée sur un verrou déverrouillé.

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}")

Production :

counter=10
counter=30
The final counter is 30

Nous avons créé une variable globalement partagée counter=0 et deux threads t1 et t2. Les deux threads ciblent la même fonction increase(). La fonction increase(by, lock) prend deux paramètres. Le premier paramètre est la quantité par laquelle il incrémentera counter, et le deuxième paramètre est une instance de la classe Lock. En plus des déclarations précédentes, nous avons également créé une instance Lock de la classe Lock à l’intérieur du module threading de Python. Ce paramètre lock de la fonction increase(by, lock) verrouille l’accès à la variable counter avec la fonction lock.acquire() tant qu’elle est modifiée par n’importe quel thread et déverrouille le verrou avec la fonction lock.release() lorsqu’un thread a modifié la variable counter. Le thread t1 incrémente la valeur de counter de 10, et le thread t2 incrémente la valeur de counter de 20.

En raison du verrou de thread, la condition de concurrence ne se produit pas et la valeur finale de counter est 30.

Thread Lock Utilisation de with lock: en Python

Le problème avec la méthode précédente est que nous devons soigneusement déverrouiller chaque variable verrouillée lorsqu’un thread a terminé le traitement. Si ce n’est pas fait correctement, notre variable partagée ne sera accessible que par le premier thread, et aucun autre thread n’aura accès à la variable partagée. Ce problème peut être évité en utilisant la gestion de contexte. Nous pouvons utiliser avec verrou : et placer tout notre code critique à l’intérieur de ce bloc. C’est un moyen beaucoup plus facile d’éviter les conditions de course. L’extrait de code suivant montre l’utilisation de with lock: pour empêcher la condition de concurrence en Python.

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}")

Production :

counter=10
counter=30
The final counter is 30

Nous avons placé notre code pour incrémenter counter à l’intérieur du bloc with lock:. Le thread t1 incrémente la valeur de counter de 10, et le thread t2 incrémente la valeur de counter de 20. La condition de concurrence ne se produit pas, et la valeur finale de counter est 30. De plus , Nous n’avons pas à nous soucier du déverrouillage du verrou de fil.

Les deux méthodes font parfaitement leur travail, c’est-à-dire que les deux méthodes empêchent la condition de concurrence de se produire, mais la deuxième méthode est de loin supérieure à la première car elle nous évite les maux de tête liés au verrouillage et au déverrouillage des verrous de thread. Il est également beaucoup plus propre à écrire et plus facile à lire que la première méthode.

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

Article connexe - Python Thread