En voulant poster un message dans le forum Programmation (il y a une minute environ), je me retrouve avec une erreur interne (à deux reprises et le message ne se poste pas). Voici le message en question :
Titre : Conflits d’écriture entre threads (malgré le GIL)
Tags : thread, python
Bonjour,
Dans le cadre de ce tutoriel, j’ai voulu expliquer l’intérêt de l’exclusion mutuelle entre threads en Python. J’ai donc écrit ce bout de code :
import time
from threading import Thread
N = 1000000
i = 0
class IncrThread(Thread):
def run(self):
global i
# On effectue plus d'un seul incrément pour augmenter la probabilité
# de conflit entre les threads
for _ in range(N):
i += 1
def run(thread):
global i
i = 0
t1 = thread()
t2 = thread()
start = time.time()
# Les méthodes `t1.run()` et `t2.run()` sont exécutées en parallèle. Elles vont chacune
# incrémenter `i` en parallèle.
t1.start()
t2.start()
# On attend que `t1` et `t2` terminent, c'est-à-dire qu'ils aient chacun
# incrémenté `i` `N` fois.
t1.join()
t2.join()
end = time.time()
# Comme `i` a en théorie été incrémentée `N` fois par chacun des threads,
# on s'attend à ce qu'elle soit égale à `2N`.
print('{0:.2f}'.format(end-start), 'secondes, 2N-i =', 2*N-i)
if __name__ == '__main__':
print('Sans exclusion mutuelle :')
run(IncrThread)
Il me donne :
Sans exclusion mutuelle :
0.27 secondes, 2N-i = 709582
Et quand on ajoute des verrous :
import time
from threading import Thread, Lock
N = 1000000
i = 0
class LockedIncrThread(Thread):
def __init__(self, lock):
super().__init__()
self.lock = lock
def run(self):
global i
for _ in range(N):
# On utilise le verrou le moins longtemps possible pour ne pas bloquer
# excessivement les autres threads. C'est pourquoi la ressource est
# réservée dans la boucle et non pas à l'extérieur.
with self.lock:
i += 1
# ...
if __name__ == '__main__':
print('Avec exclusion mutuelle :')
# On crée un seul verrou pour tous les threads
lock = Lock()
run(lambda: LockedIncrThread(lock))
On obtient :
Avec exclusion mutuelle :
3.85 secondes, 2N-i = 0
J’ai été surpris parce qu’il me semblait que, justement, le GIL en Python empêchait de faire de la vraie concurrence avec des threads et que poser des verrous était inutiles.
Qu’ai-je manqué ?
Merci.
Merci.
+0
-0