Python Language Global Interpreter Lock (GIL) et les threads de blocage


Exemple

Beaucoup de choses ont été écrites sur le GIL de Python . Cela peut parfois causer de la confusion lorsque vous traitez des applications multithread (à ne pas confondre avec les multiprocessus).

Voici un exemple:

import math
from threading import Thread

def calc_fact(num):
    math.factorial(num)

num = 600000
t = Thread(target=calc_fact, daemon=True, args=[num])
print("About to calculate: {}!".format(num))
t.start()
print("Calculating...")
t.join()
print("Calculated")

Vous vous attendriez à voir Calculating... imprimé immédiatement après le démarrage du thread, après tout, nous voulions que le calcul ait lieu dans un nouveau thread! Mais en réalité, vous le voyez imprimé une fois le calcul terminé. C'est parce que le nouveau thread s'appuie sur une fonction C ( math.factorial ) qui verrouille le GIL lors de son exécution.

Il y a plusieurs manières de contourner cela. La première consiste à implémenter votre fonction factorielle en Python natif. Cela permettra au thread principal de prendre le contrôle pendant que vous êtes dans votre boucle. L'inconvénient est que cette solution sera beaucoup plus lente, car nous n'utilisons plus la fonction C.

def calc_fact(num):
    """ A slow version of factorial in native Python """
    res = 1
    while num >= 1:
        res = res * num
        num -= 1
    return res

Vous pouvez également sleep pendant un certain temps avant de commencer votre exécution. Remarque: cela ne permettra pas à votre programme d’interrompre le calcul qui se produit à l’intérieur de la fonction C, mais cela permettra à votre thread principal de continuer après l’apparition, ce à quoi vous pouvez vous attendre.

def calc_fact(num):
    sleep(0.001)
    math.factorial(num)