Comprendre le verrouillage de l'interprète global de Python
Published: 2024-01-26 16:41:24

Qu'est-ce que le Global Interpreter Lock (GIL) de Python ?
----------------------------------------------------------

Dans le royaume de Python, une créature infâme connue sous le nom de Global Interpreter Lock (GIL) se cache, affectant les performances et le threading. Lorsque les programmeurs s'aventurent au cœur de Python pour comprendre, défier et éventuellement transcender le GIL, ils rencontrent à la fois ses limites et son impact sur la mise en œuvre de Python dans divers domaines, y compris la science des données et l'apprentissage automatique.

### Mise à jour du Redditor [zurtex](https://www.reddit.com/user/zurtex/) sur la GIL désactivée

[Voir le commentaire de zurtex sur reddit](https://www.reddit.com/r/Python/comments/15i5je7/comment/juu7usg/)

L'option `--disable-gil` ne débarque pas pour CPython 3.12. En fait, la branche CPython 3.12 est maintenant verrouillée pour les commits en dehors de l'équipe de gestion des versions alors qu'ils se préparent pour la version rc1.

De plus, un changement aussi important n'arriverait que sur la branche principale (actuellement 3.13), et non directement sur une branche de version mineure une fois que cette branche est séparée de la branche principale, ce qui s'est produit il y a plusieurs mois pour la 3.12, bien avant l'annonce de l'intention d'accepter la PEP.

La PEP 703 _pourrait_ atterrir sur CPython 3.13, mais le comité de pilotage a été très clair sur le fait qu'il n'y avait pas de problème à ce qu'elle glisse jusqu'à CPython 3.14. Il est donc possible que l'on se trompe lorsqu'il est dit qu'elle atterrira_"bientôt_" :

-   PEP 703 est à l'état de **projet**, il n'a pas encore été officiellement accepté.
    
-   Sam Gross est en vacances en ce moment et aurait beaucoup de travail à faire pour rebasculer la [branche nogil](https://github.com/colesbury/nogil-3.12) dans la [branche](https://github.com/colesbury/nogil-3.12) principale et au moins traiter plusieurs problèmes soulevés par l'équipe Faster CPython qui peuvent provoquer des plantages en utilisant du code Python pur avant qu'il ne soit envisagé d'atterrir dans la branche principale.
    

CPython 3.12 désactive le verrouillage global de l'interpréteur (GIL)
---------------------------------------------------------------------

Le script `./configure` pourrait _bientôt_ définir la macro `Py_NOGIL` dans le fichier `Python/patchlevel.h.` Cela signifie que la façon de désactiver le GIL ressemble à ceci :

```js
git clone -b nogil-3.12 https://github.com/colesbury/nogil-3.12.git
cd nogil-3.12
./configure --disable-gil
make
```

_Notez que l'_ _option__`--disable-gil`_ _est un projet PEP. Même s'il est indiqué qu'il n'est pas reconnu, les commandes ci-dessus créeront des binaires avec la GIL désactivée._

**Désactiver la GIL au moment de la compilation :**[https://peps.python.org/pep-0703/#build-configuration-changes](https://peps.python.org/pep-0703/#build-configuration-changes)

**Réactiver la GIL au moment de l'exécution**[:](https://peps.python.org/pep-0703/#pythongil-environment-variable) https://peps.python.org/pep-0703/#pythongil-environment-variable

L'origine et l'objectif de la GIL de Python et le rôle du verrouillage global de l'interpréteur
-----------------------------------------------------------------------------------------------

Introduit à l'origine dans Python 1.5, le GIL était un mécanisme conçu pour améliorer la stabilité. Il s'agit essentiellement d'un mutex (ou d'un verrou) qui permet à un seul thread d'exécuter le bytecode Python à la fois. Il s'agissait principalement d'une solution pour gérer le multithreading et faciliter la gestion de la mémoire, en créant un sentiment de sécurité et de prévisibilité dans l'environnement Python.

Les limites du verrouillage global de l'interpréteur (GIL) de Python
--------------------------------------------------------------------

Cependant, ce mécanisme de sécurité a un coût. Malgré son intention initiale, le GIL est devenu une source d'entraves aux performances, entraînant l'absence de réponse des programmes Python lors d'opérations d'E/S ou d'appels système.

Le multithreading de Python est devenu pratiquement inutile pour les tâches à forte intensité de CPU à cause de ce verrou, ce qui a créé un obstacle majeur. En dépit de la simplicité et de la sécurité qu'il offrait, nous avons été appelés à nous lancer dans une aventure pour défier et surmonter cette limitation.

Bibliothèques asynchrones et multiprocessus : les meilleurs amis de la concurrence en Python
--------------------------------------------------------------------------------------------

Avant de remettre en question la GIL elle-même, la première réaction a été d'atténuer ses limites. Les bibliothèques d'E/S asynchrones ont été introduites pour les tâches à forte concurrence. Ces bibliothèques permettent d'effectuer des opérations d'E/S et des appels système sans interférer avec la GIL.

Pour les charges de travail pesant sur le processeur, le multiprocessing est apparu, permettant à plusieurs exécutions de Python de fonctionner simultanément. Cela a été possible grâce au mécanisme de passage de messages, où les threads peuvent communiquer et partager les charges de travail. Ces outils fournissent une solution de contournement pour la GIL, vous permettant de l'éviter. Mais ces bibliothèques ne résoudront pas le problème sous-jacent de la GIL.L'exploration des alternatives à CPython, telles que [IronPython](https://ironpython.net/) et [Jython](https://www.jython.org/), révèle comment elles gèrent le multithreading différemment. IronPython, par exemple, s'intègre au cadre .NET et bénéficie de son modèle de threading, tandis que Jython, qui fonctionne sur la machine virtuelle Java, tire parti des capacités de threading de Java. Ces implémentations de Python donnent un aperçu des différentes approches en matière de concurrence, mettant en évidence la polyvalence du langage de programmation, qui s'adapte à diverses plateformes et à divers environnements.

La décision de désactiver le py.GIL : préparez-vous, le défi commence
---------------------------------------------------------------------

Avec la sortie de CPython 3.12, le voyage a pris une tournure passionnante : la GIL pouvait désormais être désactivée. Cette initiative, qui nécessite une recompilation de Python avec le drapeau `--disable-gil`, promettait des améliorations de performances potentielles spectaculaires. Cependant, elle nous a également propulsés sur un terrain beaucoup plus risqué. Quelles seraient les implications d'une décision aussi radicale ?

Les implications de la désactivation de la GIL de Python : la sécurité n'est plus de mise
-----------------------------------------------------------------------------------------

La désactivation du verrouillage global de l'interpréteur a permis à plusieurs threads d'exécuter simultanément le bytecode Python. Cela signifiait une opportunité d'augmenter les performances de manière significative. Cependant, le risque était considérable : la désactivation supprimait entièrement la couverture de sécurité intégrée de Python, laissant la place à des pannes potentielles dues à des problèmes liés aux ressources partagées et à la gestion de la mémoire.

De vrais threads dans Python : de vraies récompenses
----------------------------------------------------

Après avoir désactivé la GIL, nous pouvions désormais envisager une utilisation plus novatrice des threads. Même les tâches gourmandes en ressources CPU peuvent être réparties entre les threads, ce qui peut être considéré comme une récompense significative de cette épreuve. Cependant, cela nécessitait une gestion méticuleuse de la mémoire partagée et des ressources, sous peine de conduire à un désastre - nous avions effectivement libéré Python de ses contraintes de sécurité.

Enseignements et conclusions sur la GIL de Python
-------------------------------------------------

Malgré les émotions et les possibilités offertes par la désactivation de la GIL, il est apparu clairement que la conception originale de Python a ses mérites. Bien que ses limites soient flagrantes, la GIL a également fourni une protection contre les crashs potentiels, assurant la stabilité globale du système.

La désactivation de la GIL peut permettre d'améliorer les performances, mais elle s'accompagne de risques considérables. Une bonne compréhension et des précautions sont nécessaires avant de s'aventurer sur ce nouveau terrain. Il est plus judicieux d'optimiser le modèle de threading de Python, en capitalisant sur les bibliothèques d'E/S asynchrones et le multiprocessing, plutôt que de désactiver purement et simplement la GIL.

L'aventure dans la GIL de Python ne ramène pas seulement une solution potentielle, mais aussi une compréhension plus profonde du système dans son ensemble, favorisant une manière plus réfléchie et plus complexe de s'engager avec Python. Il est possible d'utiliser les meilleurs outils disponibles et d'éviter les pénalités de performance de la GIL.

Ce que je pense de la GIL Python
--------------------------------

J'ai d'abord été enthousiasmé par la possibilité de désactiver le verrouillage global de l'interpréteur (GIL) en Python, car cela promettait de nouvelles opportunités de gains de performance. Cependant, après réflexion, je pense que ce n'est pas le cas. La désactivation du GIL ne permettrait que l'utilisation de modèles de threading et de threads au sein de Python, ce dont je ne suis pas fan. La méthode que je préfère pour obtenir une grande concurrence et des programmes efficaces est d'utiliser plusieurs processus avec passage de messages.

C'est ainsi que nous avons conçu PubNub, qui dispose actuellement de nombreux clusters Kubernetes répartis dans le monde entier et dessert plus d'un milliard d'appareils sur le réseau. Nous sommes en mesure d'atteindre ce niveau de concurrence et d'échelle en suivant des modèles qui nous permettent d'exploiter pleinement les ressources que nous achetons auprès de notre fournisseur de services en nuage, Amazon Web Services. Nous n'avons pas à nous préoccuper des threads, du verrouillage ou de la sécurité de la mémoire car ce modèle de conception est mis en œuvre en C, en utilisant des interruptions de noyau d'E/S asynchrones directement via l'API de noyau epoll sous Linux. Cela nous permet de tirer pleinement parti de notre processeur sans avoir à faire du "context thrashing".

Le même effet peut être obtenu en Python. En lançant un worker Python à un seul thread dans un conteneur Docker, puis en faisant tourner plusieurs conteneurs Docker. Vous pouvez effectuer un round robin et équilibrer la charge en utilisant un équilibreur de charge, tel que [Nginx](https://www.pubnub.com/guides/nginx/), qui est un équilibreur de charge standard commun utilisé dans l'écosystème Kubernetes. Vous obtiendrez ainsi ce dont vous avez besoin. Vous voudrez ajouter une bibliothèque d'E/S asynchrones afin que le moteur Python ne se bloque pas pendant l'attente des E/S. Cela vous permettra de tirer le meilleur parti du matériel que vous avez acheté.

Si vous souhaitez simplement tirer parti de la concurrence sur un système unique, comme votre ordinateur portable, l'utilisation de la bibliothèque multiprocessus de Python est la meilleure solution. Elle fournit des mécanismes permettant de répartir les charges de travail entre les cœurs de l'unité centrale de votre système.

Questions fréquemment posées sur Python 3.12 GIL
------------------------------------------------

Nous devons couvrir quelques points supplémentaires en ce qui concerne ce que vous pouvez faire ensuite. Voici quelques questions courantes qui ont été soulevées au cours des discussions.

### Dois-je me réjouir de Python 3.12 et du nouveau drapeau --disable-gil ?

1.  Oui, si vous aimez les threads et travailler avec les défis et les efforts de code supplémentaires.
    
2.  **Non, sinon. Il y a de meilleures options !**
    

L'intérêt de Python 3.12 et du nouveau drapeau `--disable-gil` dépend largement de votre cas d'utilisation spécifique et de votre compréhension des complexités du multithreading.

Si vous effectuez fréquemment des tâches gourmandes en ressources processeur et que vous êtes versé dans la gestion prudente des threads et de la programmation, l'option permettant de désactiver le verrouillage global de l'interpréteur (GIL) pourrait être bénéfique. Cette fonctionnalité peut potentiellement apporter des améliorations considérables en termes de performances, car plusieurs threads peuvent exécuter le bytecode Python simultanément sans que le GIL ne les ralentisse.

Cette fonctionnalité augmente également les risques. La GIL de Python joue un rôle crucial dans le maintien de l'intégrité des objets Python en empêchant l'exécution simultanée de bytecodes Python par plusieurs threads. Le développement de programmes threadés sans GIL nécessite une compréhension approfondie de la sécurité des threads et de la synchronisation, car il vous incombe désormais de veiller à ce qu'aucune course de données ou incohérence ne se produise.

De nombreuses bibliothèques standard de Python reposent sur l'existence de la GIL pour la sécurité des threads, et celles-ci peuvent ne pas fonctionner correctement, voire pas du tout, si vous choisissez de la désactiver.

Ainsi, bien que cette fonctionnalité puisse potentiellement offrir des améliorations significatives en termes de performances dans des contextes spécifiques, elle ne doit pas être utilisée à la légère ou de manière universelle. Comme tout outil puissant, il faut le comprendre, le respecter et l'utiliser correctement et efficacement.

Pour la plupart des développeurs Python, en particulier ceux qui ne développent pas d'applications multithread à forte intensité de CPU, l'arrivée des bibliothèques asynchrones et des modules multiprocessus dans la bibliothèque standard de Python fournit des mécanismes suffisants pour gérer la concurrence et le parallélisme, ce qui rend la désactivation de la GIL moins importante.

### Qu'est-ce qui devient disponible en désactivant la GIL ?

La désactivation du verrouillage global de l'interpréteur (GIL) permet principalement aux programmes Python multicœurs d'obtenir une véritable exécution simultanée des threads, ce qui peut conduire à une amélioration significative des performances pour les tâches liées au processeur.

Voici un bref résumé de ce qui devient disponible lorsque le GIL est désactivé :

1.  **Exécution simultanée de threads :** Lorsque la GIL est désactivée, plusieurs threads peuvent exécuter des bytecodes Python simultanément sans attendre le verrou. Cela peut conduire à une meilleure utilisation des processeurs multicœurs.
    
2.  **Meilleures performances pour les tâches multithreads liées au processeur :** Pour les tâches liées au processeur qui ont été divisées en plusieurs threads, la désactivation de la GIL peut potentiellement conduire à une amélioration significative des performances, car chaque thread peut s'exécuter simultanément sur différents cœurs.
    
3.  **Plus de contrôle sur la synchronisation des threads :** La désactivation de la GIL signifie que les développeurs doivent désormais gérer eux-mêmes la synchronisation des threads. Bien que cela nécessite une compréhension approfondie du multithreading, cela donne également plus de contrôle sur les opérations des threads et pourrait potentiellement permettre un réglage plus nuancé et optimisé des performances.
    

Il est important d'être conscient des inconvénients potentiels. La désactivation de la GIL supprime un garde-fou qui garantit un fonctionnement sans thread pour de nombreuses bibliothèques et opérations Python. Par conséquent, les complexités et les pièges potentiels associés au multithreading, tels que les conditions de course, les blocages et autres problèmes de synchronisation, deviennent la responsabilité du développeur, qui doit les traiter et les gérer.

### La désactivation de la GIL entraînera-t-elle une amélioration des performances ?

L'amélioration des performances en désactivant le verrouillage global de l'interpréteur (GIL) dépend de la nature de votre programme Python.

Si votre programme utilise fortement les tâches liées au processeur et a été conçu en utilisant le multithreading, vous pouvez potentiellement constater une amélioration significative des performances. En effet, lorsque la GIL est désactivée, plusieurs threads peuvent exécuter des bytecodes Python sur différents cœurs en même temps, ce qui permet une meilleure utilisation des processeurs multicœurs.

Lorsque votre programme est principalement lié aux E/S (par exemple, il passe la plupart de son temps à attendre des réponses du réseau, à lire sur le disque, etc.), la GIL est moins susceptible d'être un goulot d'étranglement et sa désactivation ne produirait probablement que des améliorations minimes, voire aucune, des performances. En fait, dans les scénarios liés aux E/S, l'exploitation correcte de la programmation asynchrone et des bibliothèques de concurrence peut être plus bénéfique que la désactivation de la GIL.

Si votre programme n'est pas conçu pour gérer correctement la synchronisation des threads, la désactivation de la GIL pourrait en fait dégrader les performances ou provoquer un comportement inattendu dû à des conditions de course et à d'autres pièges liés au multithreading.

Bien qu'il soit possible d'augmenter les performances en désactivant la GIL dans des scénarios spécifiques, il est nécessaire de faire preuve d'une grande prudence et d'une grande expertise pour gérer efficacement et en toute sécurité un véritable multithreading en Python sans la GIL. Pour de nombreuses applications, l'utilisation d'autres fonctionnalités de Python, comme le module multiprocessing ou async IO pour gérer les tâches parallèles et concurrentes, peut être une approche plus sûre et plus efficace.

### Comment désactiver la GIL ?

Pour désactiver le verrouillage global de l'interpréteur (GIL) dans Python, vous devez essentiellement configurer et compiler Python avec l'option --disable-gil. Cette méthode nécessite la compilation de Python à partir des sources. De plus, gardez à l'esprit que la fonctionnalité permettant de désactiver le GIL se trouve dans CPython v3.14 possible et plus. Voici les étapes à suivre :

1\. Téléchargez le fichier source CPython pour Python 3.1X ou plus récent. Il est plus probable qu'il s'agisse de Python 3.14. Vous pouvez cloner le dépôt depuis Github.

`git clone -b 3.1X https://github.com/python/cpython.git`

2\. Allez dans le répertoire CPython téléchargé.

`cd cpython`

3\. Exécutez le script de configuration avec l'option --disable-gil.

`./configure --disable-gil`

4\. Maintenant, construisez Python.

`make`

Cette opération ne doit pas être effectuée à la légère, car elle pourrait entraîner des problèmes de threading si le code n'est pas correctement sécurisé pour les threads. Cette méthode est plus adaptée aux développeurs qui ont besoin d'un véritable multithreading et qui sont prêts à gérer les complexités qui surviennent lorsque la sécurité des threads n'est pas garantie par Python. Assurez-vous toujours que votre code et toutes les bibliothèques que vous utilisez sont thread-safe avant de désactiver la GIL.

### Comment réactiver la GIL avec la variable d'environnement ?

Le verrouillage global de l'interpréteur (GIL) de Python peut être réactivé en définissant une variable d'environnement appelée PYTHONGIL à 1. Cela permet de forcer la réactivation du GIL, même s'il a été désactivé au moment de la compilation.

La définition de la variable peut se faire de différentes manières en fonction de votre système d'exploitation. Voici comment procéder pour les systèmes Unix, y compris Linux et MacOS :

`export PYTHONGIL=1`

`python my-app.py`

Pour les systèmes Windows, vous pouvez définir des variables d'environnement à l'aide de la commande :

`set PYTHONGIL=1`

`python my-app.py`

N'oubliez pas que ces commandes ne définissent la variable d'environnement que pour la session de terminal en cours. Si vous souhaitez la définir de manière persistante, vous devez ajouter la commande appropriée à votre fichier d'initialisation du shell (comme .bashrc ou .bash\_profile pour le shell bash dans les systèmes Unix) ou définir la variable dans les propriétés du système sous Windows.

N'oubliez pas que vous devrez exécuter votre programme Python à partir de la même session de terminal que celle où vous avez défini cette variable d'environnement pour en voir l'effet sur votre programme.

### La désactivation de la GIL présente-t-elle des risques ?

Oui, il existe des risques considérables associés à la désactivation du verrouillage global de l'interprète (GIL) dans Python. Les principaux risques sont les suivants :

1.  **Problèmes de sécurité des threads :** La GIL assure un certain degré de sécurité des threads en ne permettant pas à plusieurs threads d'exécuter simultanément des bytecodes Python. En désactivant la GIL, la responsabilité d'assurer la sécurité des threads incombe au développeur. Cela peut entraîner des problèmes tels que des conditions de course, des corruptions de données et des plantages si plusieurs threads accèdent à des données partagées ou les modifient simultanément sans synchronisation adéquate.
    
2.  **Problèmes de compatibilité :** De nombreuses bibliothèques Python, dont certaines font partie de la bibliothèque standard, sont écrites en supposant que la GIL est activée. Ces bibliothèques peuvent utiliser des opérations non sûres pour les threads, qui sont sûres sous la GIL mais peuvent causer des problèmes lorsque la GIL est désactivée.
    
3.  **Dégradation des performances : Dans**certains cas, la désactivation de la GIL peut entraîner une baisse des performances en raison de l'augmentation des frais généraux liés à la gestion de plusieurs threads et à la synchronisation de l'accès aux données partagées.
    
4.  **Difficulté de débogage :** Le débogage d'applications multithreads sans GIL peut s'avérer plus complexe en raison de la synchronisation supplémentaire des threads qui doit être assurée manuellement.
    
5.  **Risque de blocage :** Sans la GIL, vous pouvez également être plus enclin à rencontrer des blocages, où deux ou plusieurs threads attendent indéfiniment que l'autre libère une ressource.
    

La désactivation de la GIL peut potentiellement améliorer les performances de certaines applications multithreads liées au processeur, mais elle est considérée comme une opération risquée et n'est généralement pas recommandée, à moins que vous ne soyez très familiarisé avec la synchronisation des threads et que vous soyez prêt à gérer les complexités et les pièges potentiels du multithreading.

### Existe-t-il d'autres solutions que la désactivation de la GIL ?

Oui, il existe plusieurs autres façons de gérer le traitement concurrent et parallèle en Python sans avoir besoin de désactiver le verrouillage global de l'interpréteur (GIL) :

1.  **Le multithreading :** Pour les tâches qui sont en grande partie liées aux E/S (comme faire plusieurs requêtes sur le web, lire un fichier ou une base de données, etc.), le module de threading de Python peut être utilisé pour obtenir la simultanéité. La GIL est un goulot d'étranglement pour les tâches liées au processeur, mais les tâches liées aux E/S peuvent libérer la GIL et laisser d'autres threads s'exécuter lorsqu'ils sont en attente d'E/S.
    
2.  **Multitraitement :** Le module multiprocessus de Python contourne la GIL en créant des processus d'interprétation Python distincts et permet donc un véritable parallélisme dans les tâches liées à l'unité centrale. Cela s'accompagne d'une surcharge de communication inter-processus et peut utiliser beaucoup plus de mémoire, mais c'est un moyen robuste de contourner la GIL.
    
3.  **Programmation asynchrone :** Le module asyncio de Python et les bibliothèques asynchrones comme Twisted et Tornado permettent de gérer plus efficacement plusieurs tâches liées aux E/S en utilisant une boucle d'événements. Ce modèle permet de tirer pleinement parti des temps d'attente inhérents aux tâches liées aux E/S pour exécuter d'autres tâches et améliorer ainsi le débit de votre programme.
    
4.  **NumPy/SciPy pour le traitement numérique :** Ces bibliothèques traduisent une grande partie de leurs calculs en code compilé où la GIL peut être évitée, ce qui les rend excellentes pour les calculs numériques, et elles sont bien optimisées pour les opérations vectorielles.
    
5.  **Extensions Cython ou C :** Si les performances sont critiques, vous pouvez écrire des extensions C ou utiliser Cython pour écrire des parties de votre code au niveau C. Dans le code C natif, la GIL peut être libérée, ce qui atténue ses inconvénients.
    
6.  **Bibliothèques de calcul parallèle :** Des outils tels que joblib, Dask, Ray et d'autres fournissent des environnements de haut niveau pour effectuer des calculs parallèles qui peuvent utiliser plusieurs processeurs et gérer efficacement le partage de la mémoire.
    

La meilleure solution dépend de votre cas particulier et du type de problème que vous essayez de résoudre. Il est toujours important de comprendre les compromis de chaque option pour s'assurer que vous faites le choix qui correspond le mieux à vos besoins.

Comment PubNub peut-il vous aider ?
===================================

Cet article a été publié à l'origine sur [PubNub.com](https://www.pubnub.com/blog/understanding-pythons-global-interpreter-lock/)

Notre plateforme aide les développeurs à construire, livrer et gérer l'interactivité en temps réel pour les applications web, les applications mobiles et les appareils IoT.

La base de notre plateforme est le réseau de messagerie périphérique en temps réel le plus grand et le plus évolutif de l'industrie. Avec plus de 15 points de présence dans le monde, 800 millions d'utilisateurs actifs mensuels et une fiabilité de 99,999 %, vous n'aurez jamais à vous soucier des pannes, des limites de concurrence ou des problèmes de latence causés par les pics de trafic.

Découvrez PubNub
----------------

Découvrez le [Live Tour](https://www.pubnub.com/tour/introduction/) pour comprendre les concepts essentiels de chaque application alimentée par PubNub en moins de 5 minutes.

S'installer
-----------

Créez un [compte PubNub](https://admin.pubnub.com/signup/) pour un accès immédiat et gratuit aux clés PubNub.

Commencer
---------

La [documentation PubNub](https://www.pubnub.com/docs) vous permettra de démarrer, quel que soit votre cas d'utilisation ou votre [SDK](https://www.pubnub.com/docs).