logo

Qu’est-ce que GIL en Python ? Verrouillage global de l'interprète

Ce tutoriel se concentrera sur l'un des sujets importants de Python, GIL. Nous aborderons également l'impact du GIL sur les performances des programmes Python avec l'implémentation du code. Avant d’aborder ce sujet, ayons une idée de base du GIL.

GIL ou Global Interpreter Lock

Python Global Interpreter Lock ou GIL est une partie importante de la programmation multithread. Il s'agit d'un type de verrouillage de processus utilisé lorsque vous travaillez avec plusieurs processus. Il donne le contrôle à un seul thread. Généralement, Python utilise un seul thread pour exécuter un seul processus. Nous obtenons le même résultat de performances des processus monothread et multithread utilisant le GIL. Il restreint la réalisation du multithreading en Python car il empêche les threads et fonctionne comme un seul thread.

Remarque - Python ne prend pas en charge le multithreading car les packages de threading ne peuvent pas nous permettre d'utiliser les plusieurs cœurs de processeur.

Pourquoi les développeurs Python utilisent GIL ?

Python fournit la fonctionnalité unique de compteur de références, utilisée pour la gestion de la mémoire. Le compteur de références compte le nombre total de références effectuées en interne dans Python pour attribuer une valeur à un objet de données. Lorsque le nombre de références atteint zéro, la mémoire attribuée à l'objet est libérée. Voyons l'exemple ci-dessous.

Exemple -

 import sys a = [] b = a sys.getrefcount(a) 

Le principal problème avec la variable de nombre de références est qu'elle peut être affectée lorsque deux ou trois threads tentent d'augmenter ou de diminuer sa valeur simultanément. C’est ce qu’on appelle la condition de concurrence. Si cette condition se produit, cela peut entraîner une fuite de mémoire qui n'est jamais libérée. Il peut planter ou bugs dans le programme Python.

GIL nous aide à supprimer une telle situation en utilisant les verrous sur toutes les structures de données partagées entre les threads afin qu'elles ne soient pas modifiées de manière incohérente. Python fournit un moyen simple d'implémenter le GIL car il gère la gestion de la mémoire thread-safe. GIL nécessite d'offrir un seul verrou à un thread pour le traitement en Python. Cela augmente les performances d'un programme monothread car un seul verrou doit être géré. Il aide également à créer n’importe quel programme lié au processeur et évite les blocages.

L'impact sur les programmes Python multithread

Il existe une différence entre les limites de CPU dans leurs performances et les limites d'E/S pour un programme Python typique ou n'importe quel programme informatique. Les programmes liés au processeur poussent généralement le processeur à ses limites. Ces programmes sont généralement utilisés pour des calculs mathématiques tels que les multiplications matricielles, la saisie, le traitement d'images, etc.

Les programmes liés aux E/S sont les programmes qui passent du temps à obtenir des entrées/sorties pouvant être générées par l'utilisateur, le fichier, la base de données, le réseau, etc. De tels programmes doivent attendre un certain temps jusqu'à ce que la source fournisse l'entrée. D’un autre côté, la source a également son propre temps de traitement. Par exemple, un utilisateur réfléchit à ce qu'il doit saisir comme entrée.

Comprenons l'exemple suivant.

Exemple -

 import time from threading import Thread COUNT = 100000000 def countdown(num): while num>0: num -= 1 start_time = time.time() countdown(COUNT) end_time = time.time() print('Time taken in seconds -', end_time - start_time) 

Sortir:

 Time taken in seconds - 7.422671556472778 

Maintenant, nous modifions le code ci-dessus en exécutant les deux threads.

Exemple - 2 :

 import time from threading import Thread COUNT = 100000000 def countdown(num): while num>0: num -= 1 thread1 = Thread(target=countdown, args=(COUNT//2,)) thread2 = Thread(target=countdown, args=(COUNT//2,)) start_time = time.time() thread1.start() thread2.start() thread1.join() thread2.join() end_time = time.time() print('Time taken in seconds -', end_time - start_time) 

Sortir:

 Time taken in seconds - 6.90830135345459 

Comme nous pouvons le voir, les deux codes ont mis le même temps à se terminer. GIL a empêché les threads liés au CPU de s'exécuter en parallèle dans le deuxième code.

Pourquoi le GIL n’a-t-il pas encore été supprimé ?

De nombreux programmeurs se plaignent de cela, mais Python ne peut pas apporter des changements aussi importants que la suppression de GIL. Une autre raison est que GIL n’est pas amélioré pour le moment. Si cela change dans Python 3, cela créera de sérieux problèmes. Au lieu de supprimer GIL, le concept GIL peut être amélioré. Selon Guido van Rossom -

'Je souhaiterais un ensemble de correctifs dans Py3k uniquement si les performances d'un programme monothread (et d'un programme multithread mais lié aux E/S) ne diminuent pas'.

Il existe également de nombreuses méthodes disponibles qui résolvent le même problème résolu par le GIL, mais elles sont difficiles à mettre en œuvre.

Comment gérer le GIL de Python

L'utilisation du multitraitement est le moyen le plus approprié d'empêcher le programme de GIL. Python propose différents interpréteurs pour chaque processus à exécuter, donc dans ce scénario, le thread unique est fourni à chaque processus en multitraitement. Comprenons l'exemple suivant.

Exemple -

 from multiprocessing import Pool import time COUNT = 50000000 def countdown(num): while num>0: num -= 1 if __name__ == '__main__': pool = Pool(processes=2) start_time = time.time() r1 = pool.apply_async(countdown, [COUNT//2]) r2 = pool.apply_async(countdown, [COUNT//2]) pool.close() pool.join() end_time = time.time() print('Time taken in seconds -', end_time - start_time) 

Sortir:

 Time taken in seconds - 3.3707828521728516 

Il peut sembler que les performances sont améliorées, mais la gestion des processus a ses propres frais généraux et plusieurs processus sont plus lourds que plusieurs threads.

Conclusion

Dans ce tutoriel, nous avons discuté du GIL et de la manière dont nous pouvons l'utiliser. Il donne le contrôle à un seul thread à exécuter à la fois. Ce didacticiel explique également pourquoi GIL est important pour les programmeurs Python.