
Partager:
Max est un défenseur des développeurs Python et un ingénieur logiciel qui s'intéresse aux API de communication, à l'apprentissage automatique, à l'expérience des développeurs et à la danse ! Il a suivi une formation en physique, mais il travaille désormais sur des projets open-source et fabrique des objets qui améliorent la vie des développeurs.
Suppression de la GIL de Python : c'est fait !
Temps de lecture : 9 minutes
Introduction
Le verrouillage global de l'interpréteur (GIL) en Python est un mécanisme de verrouillage qui garantit qu'un seul thread peut exécuter le code Python à la fois, même sur les processeurs multicœurs. Bien que cela présente certains avantages, cela signifie qu'il n'est pas facile de tirer parti de plusieurs cœurs de processeur pour le traitement parallèle en Python.
Récemment, le Conseil directeur de Python a indiqué qu'il avait l'intention d'approuver le document PEP 703une proposition visant à créer une version de CPython, l'interpréteur Python le plus populaire, sans la GIL. Cette proposition a des implications considérables pour le développement de Python à l'avenir, il est donc utile de comprendre ce qui se passe.
Dans ce billet, nous allons discuter des raisons pour lesquelles nous avons la GIL en Python, des raisons pour lesquelles nous pourrions vouloir la supprimer, et du travail qui est actuellement en cours pour y parvenir.
Pourquoi avons-nous la GIL ?
La GIL simplifie la gestion des threads et protège contre les conditions de course et la corruption de la mémoire en Python, ce qui permet aux développeurs d'écrire plus facilement du code concurrent en toute sécurité. Elle a été introduite lorsque la prise en charge des threads a été ajoutée à Python dans les premiers jours du langage.
Compatibilité
De nombreux paquets Python (et l'interpréteur Python principal, CPython) font un usage intensif des extensions C, qui ne sont pas intrinsèquement sûres pour les threads. Il est possible que plusieurs threads essaient d'accéder aux mêmes ressources, ce qui peut avoir des effets extrêmement négatifs. La GIL a rendu la création et l'utilisation d'extensions C plus sûres, ce qui a permis aux développeurs des années 90 de commencer plus facilement à utiliser Python pour créer des logiciels, favorisant ainsi l'adoption du langage.
Collecte de déchets et comptage de références
L'autre raison importante est liée à la manière dont Python gère le ramassage des ordures. Le ramassage des ordures est un processus de gestion automatique de la mémoire par lequel l'interpréteur suit et récupère la mémoire occupée par des objets qui ne sont plus référencés ou accessibles dans le programme. En Python, il existe deux méthodes principales de ramassage des ordures, mais la plus importante est un processus appelé comptage de références.
Le comptage de références en Python est un moyen efficace de gérer la mémoire et de s'assurer que les ressources sont libérées lorsqu'elles ne sont plus utilisées, ce qui permet d'éviter les fuites de mémoire dans les programmes Python. Le comptage de références fonctionne de la manière suivante :
Chaque objet garde la trace du nombre de références qui pointent vers lui.
Lorsque le nombre de références d'un objet tombe à zéro, cela signifie qu'il n'y a plus de références à cet objet dans le programme.
Cela indique que l'objet n'est plus nécessaire.
Le système de gestion de la mémoire de Python récupère automatiquement la mémoire occupée par l'objet, le supprimant de fait.
Sans la GIL, plusieurs threads s'exécutant simultanément pourraient manipuler le nombre de références d'objets en même temps, ce qui entraînerait des conditions de course et une corruption de la mémoire. La GIL agit comme un garde-fou, permettant à un seul thread d'exécuter le bytecode Python à la fois, évitant ainsi ces problèmes potentiels.
Pourquoi voulons-nous supprimer la GIL ?
Si la GIL peut simplifier l'écriture de code sans trop se préoccuper de la sécurité des threads, elle peut également limiter les gains de performance que vous pourriez attendre de l'utilisation de plusieurs threads dans les tâches liées au processeur. Pour les tâches liées aux E/S, telles que les requêtes HTTP ou les opérations sur les fichiers, la GIL n'a pas autant d'impact, et vous pouvez donc toujours bénéficier du multithreading dans ces cas-là. Ainsi, si vous utilisez des threads en Python pour envoyer de nombreuses requêtes HTTP, cela pourrait améliorer les performances, mais si vous utilisez des threads pour effectuer de nombreuses tâches gourmandes en ressources processeur, ce ne sera probablement pas le cas.
Si la GIL était supprimée, nous serions en mesure d'obtenir les avantages en termes de performances du threading lors de tâches intensives pour le processeur, ce qui n'est pas le cas actuellement avec CPython.
Qu'est-ce qui ne va pas avec les autres approches visant à améliorer la concomitance ?
Le threading et le traitement asynchrone avec asyncio sont deux méthodes permettant d'améliorer les performances, mais elles ne fonctionnent que pour les opérations liées aux entrées-sorties. Cependant, il existe quelques méthodes qui fonctionnent pour les opérations liées au processeur.
Python prend en charge le multiprocessus grâce au module multiprocessing moduleet il est également possible d'écrire du code semblable à celui de Python à l'aide de Cython pour améliorer les performances. Ces deux méthodes peuvent améliorer les performances des opérations liées à l'unité centrale, mais elles présentent des inconvénients.
Multiprocessus
Le module multiprocessing de Python vous permet d'utiliser plusieurs cœurs de processeur en créant des processus séparés, chacun avec son propre interpréteur Python et son propre espace mémoire. Cette méthode est efficace pour les tâches liées à l'unité centrale, car elle contourne la GIL, qui opère sur les threads, et vous permet d'utiliser les multiples cœurs de votre machine pour une véritable exécution parallèle.
Malheureusement, la création de plusieurs processus entraîne une surcharge de ressources par rapport aux threads, ce qui se traduit par une augmentation de l'utilisation de la mémoire et du temps de démarrage. Il est également plus lent et plus compliqué de communiquer entre processus qu'entre threads. Enfin, les processus ne partagent pas la mémoire par défaut, ce qui complique le partage des données entre les processus et leur synchronisation.
Cython
Cython est un surensemble de Python qui vous permet d'écrire du code similaire à Python avec des annotations supplémentaires pour améliorer les performances. C'est un moyen d'accélérer l'exécution de votre code Python sans avoir à quitter complètement le langage Python. Cython peut accélérer l'exécution de votre code en optimisant les parties critiques tout en conservant la facilité et la lisibilité du langage Python.
Cependant, Cython a une courbe d'apprentissage plus importante que Python et nécessite la connaissance des constructions du langage C, ce qui le rend moins accessible. L'écriture et la maintenance du code Cython peuvent également être plus complexes et plus sujettes aux erreurs que l'écriture de code purement Python, en particulier lorsque vous réécrivez du code écrit à l'origine en Python.
Il existe donc deux méthodes pour améliorer les performances, mais elles présentent toutes deux des inconvénients considérables. Cela montre pourquoi il y a eu beaucoup d'intérêt pour la suppression de la GIL de Python.
Tentatives précédentes et raisons de leur échec
Plusieurs projets ont essayé de supprimer la GIL de CPython dans le passé, avec un certain succès, par exemple le projet Gilectomy par exemple. Cependant, les efforts pour supprimer la GIL s'accompagnent généralement de quelques inconvénients :
Il s'agit d'une tâche complexe susceptible d'introduire des bogues et de l'instabilité dans l'interpréteur CPython.
Ils peuvent casser le code Python existant et les bibliothèques qui s'appuient sur la GIL.
Ils peuvent augmenter l'utilisation de la mémoire.
Les extensions Python existantes, basées sur le langage C, nécessiteraient des modifications importantes.
Le principal inconvénient, cependant, est que les anciens projets sans GIL rendaient en fait le code monotâche plus lent qu'avec la GIL, ce qui signifie que si vous n'utilisiez pas le multithreading pour accélérer les opérations liées au processeur, votre code serait moins performant qu'avec CPython normal, ce qui n'est pas acceptable.
PEP 703que le Conseil directeur de Python a l'intention d'approuverchangera tout cela, et a obtenu un large soutien. Parlons-en !
Qu'est-ce que PEP 703 ? Python sans GIL, de la bonne façon
PEP 703 propose un moyen de supprimer la GIL de Python, mais parvient à éviter l'impact sur les performances du code non multithreadé qui a affecté d'autres projets Python sans GIL. Le conseil directeur de Python a indiqué le 28 juillet qu'il avait l'intention d'approuver le PEP, ouvrant ainsi la voie à l'entrée de Python sans GIL dans le courant dominant et à son éventuelle intégration par défaut dans Python.
Comment cela fonctionne-t-il ?
La principale technique permettant de supprimer la GIL sans affecter les performances d'un code à un seul fil est le comptage de références biaisé.
Dans le cadre du comptage de références biaisé, les objets accédés par un seul thread voient leur nombre de références géré plus efficacement que ceux accédés par plusieurs threads, ce qui permet d'améliorer les performances des programmes à un seul thread où la plupart des objets ne sont utilisés que par un seul thread. Cela signifie que les performances de no-GIL Python utilisant cette technique pour les opérations monotâches sont comparables à celles de Python normal, alors que les programmes Python multithreads liés à l'unité centrale sont beaucoup plus rapides !
Le projet rend également Python no-GIL plus efficace en reportant le processus de comptage des références pour les objets du module de premier niveau qui ne sont pas susceptibles de changer dans un programme Python, ainsi qu'en désignant certains objets comme "immortels" - des objets tels que None ne sont jamais détruits et n'ont donc pas besoin d'être comptés. Des modifications ont également été apportées à la manière dont la mémoire est allouée aux objets Python, ce qui facilite l'allocation de la mémoire d'une manière sûre pour les threads.
C'est très bien ! La question est donc la suivante : quand aurons-nous accès à Python sans GIL ?
Comment No-GIL Python sera mis en œuvre
Le Python Steering Council a décrit les trois étapes qu'il imagine pour que no-GIL Python devienne la version par défaut de CPython :
Court terme: Dans la version 3.13 (ou éventuellement 3.14) de Python, il est prévu d'introduire la version no-GIL en tant que mode expérimental. Ce mode sera utilisé pour obtenir des informations sur son utilisation, la conception de l'API, l'emballage et la distribution.
Mi-parcours: Une fois que la communauté sera convaincue que la version sans GIL est suffisamment soutenue, elle deviendra une option supportée mais pas une option par défaut. Une date/version cible sera fixée pour en faire l'option par défaut, le calendrier dépendant de facteurs tels que la compatibilité avec l'API et l'état de préparation de la communauté. Ils estiment que cette phase pourrait prendre un an ou deux, mais cela pourrait être plus long que cela.
Long terme: L'objectif ultime est que la version sans GIL devienne la version par défaut, éliminant ainsi la GIL sans perturber la compatibilité ascendante. Ils estiment qu'il faudra jusqu'à 5 ans pour atteindre ce stade. Tout au long de ce processus, des évaluations régulières auront lieu pour s'assurer que les progrès se poursuivent tout en évitant les problèmes de compatibilité ascendante - personne ne veut voir un autre changement comme l'épreuve de 10 ans de l'introduction de Python 3...
Conclusion
Python est sur le point de connaître un changement important : la suppression (potentielle) du verrouillage global de l'interprète (GIL), qui pourrait grandement améliorer la capacité de Python à utiliser plusieurs cœurs de processeur pour de meilleures performances. Le GIL, qui jouait le rôle d'un filet de sécurité, a empêché Python d'utiliser pleinement les processeurs modernes pour les tâches liées à l'unité centrale.
Contrairement aux tentatives précédentes, PEP 703 propose une solution intelligente, intégrant le comptage de références biaisé, le comptage de références différé et les objets immortels, entre autres techniques. Elle garantit que les programmes Python à un seul thread ne ralentiront pas, tout en donnant un coup de pouce à ceux qui utilisent plusieurs threads pour les tâches lourdes pour le processeur.
Ce changement se fera en trois étapes : d'abord avec un mode de construction expérimental, puis en tant qu'option supportée, et enfin en tant que paramètre par défaut, probablement dans les cinq prochaines années ! L'objectif est d'assurer une transition en douceur et d'éviter les problèmes de compatibilité, en apportant plus de puissance et d'efficacité à Python.
Si vous avez des questions sur cet article, n'hésitez pas à nous contacter sur notre Communauté Vonage Slack et nous poser des questions ou en nous envoyant un en nous envoyant un message sur X, anciennement connu sous le nom de Twitter.
Si vous souhaitez utiliser les API pour tout ce qui concerne les communications, comme l'envoi de SMS, les appels vocaux, les vidéoconférences, l'authentification à deux facteurs, la prévention des fraudes, et bien d'autres choses encore, vous pouvez vous inscrire à un compte de développeur Vonage gratuit (avec des crédits gratuits !).
Partager:
Max est un défenseur des développeurs Python et un ingénieur logiciel qui s'intéresse aux API de communication, à l'apprentissage automatique, à l'expérience des développeurs et à la danse ! Il a suivi une formation en physique, mais il travaille désormais sur des projets open-source et fabrique des objets qui améliorent la vie des développeurs.