Global interpreter lock

Le verrou global d'interpréteur ( GIL ) est un mécanisme utilisé dans les interpréteurs de langages informatiques pour synchroniser l'exécution des threads, de sorte qu'un seul thread natif (par processus) puisse exécuter des opérations de base à la fois (telles que l'allocation de mémoire et le comptage de références )[1]. En règle générale, un interpréteur utilisant le GIL ne verra qu'un seul thread s'exécuter à la fois, même s'il s'exécute sur un processeur multicœur. Cependant, certaines implémentations permettent au code gourmand en ressources CPU de libérer le GIL, autorisant ainsi les threads à utiliser plusieurs cœurs. CPython et Ruby MRI sont des interpréteurs bien connus disposant d'un GIL.
Concepts techniques de base
[modifier | modifier le code]Un verrou global d'interpréteur (GIL) est un verrou d'exclusion mutuelle (mutex) détenu par un thread d'interprétation de langage de programmation afin d'empêcher le partage de code non thread-safe avec d'autres threads. Dans les implémentations avec GIL, il existe toujours un GIL pour chaque processus d'interprétation.
Les applications exécutées sur des systèmes dotés d'un GIL peuvent être conçues pour utiliser des processus distincts afin d'atteindre un parallélisme complet, chaque processus possédant son propre interpréteur et, par conséquent, son propre GIL. Sans cela, le GIL peut constituer un obstacle majeur au parallélisme.
Avantages
[modifier | modifier le code]Les raisons justifiant l'utilisation d'un verrou d'interpréteur global (GIL) sont les suivantes :
- augmentation de la vitesse des programmes mono-thread (plus besoin d'acquérir ou de libérer des verrous sur toutes les structures de données séparément),
- intégration facile des bibliothèques C qui ne sont généralement pas thread-safe,
- facilité de mise en œuvre (un seul GIL est beaucoup plus simple à mettre en œuvre qu'un interpréteur sans verrou ou utilisant des verrous à grains-fins).
Une solution pour contourner le GIL consiste à créer un interpréteur séparé par thread, ce qui est trop coûteux avec la plupart des langages.
Inconvénients
[modifier | modifier le code]L'utilisation d'un verrou global d'interpréteur (GIL) dans un langage limite de fait le parallélisme possible puisqu'un unique processus interpréteur peut s'exécuter, c'est-à-dire un seul thread peut évoluer à la fois. Si le processus est presque exclusivement composé de code interprété et n'effectue pas d'appels externes à l'interpréteur susceptibles de bloquer le processus pendant de longues périodes (permettant ainsi au thread de libérer le GIL durant son traitement), le gain de vitesse sera probablement minime lors de son exécution sur une machine multiprocesseur. Quand un thread est particulièrement gourmand en ressources CPU, la signalisation entre threads peut même provoquer des ralentissement significatifs, même sur des processeurs mono-cœur[2]. Une autre situation particulièrement handicapante est lorsqu'un thread natif appelle un processus système bloquant (tel qu'un accès disque), le processus entier est bloqué, même si d'autres threads de l'application sont en attente et pourraient en théorie évoluer.
Exemples
[modifier | modifier le code]Certaines implémentations de langages qui mettent en œuvre un verrou d'interpréteur global sont CPython, l'implémentation la plus largement utilisée de Python[3],[4], et Ruby MRI, l'implémentation de référence de Ruby (où il est appelé Global VM Lock).
Les équivalents de ces langages basés sur la JVM ( Jython et JRuby ) n'utilisent pas de verrous globaux d'interpréteur. IronPython et IronRuby sont implémentés sur le Dynamic Language Runtime de Microsoft et évitent également l'utilisation d'un GIL[5].
Tcl est un exemple de langage interprété sans GIL, utilisé dans l'outil d'évaluation des performances HammerDB[6].
Exemple de code
[modifier | modifier le code]Exemple de code en Python. Notez comment un verrou est acquis et libéré entre chaque appel d'instruction. Il utilise l'objet Lock à partir du module threading de Python[7].Ici dès lors qu'un thread prend la priorité d'exécution (il acquiert le verrou), tous les autres threads sont stoppés puisqu'un seul d'entre eux peut être interprété à la fois à cause du GIL.
from threading import Lock
INSTRUCTION_TABLE = { ... }
def execute(bytecode: list) -> None:
"""Execute le code binaire."""
lock = Lock()
for (opcode, args) in bytecode:
# On récupère la priorité pour effectuer les opérations non thread-safe
lock.acquire()
INSTRUCTION_TABLE[opcode](args)
# On la libère pour permettre aux autres threads de s'éxécuter
lock.release()
Développements récents
[modifier | modifier le code]Compilation multi-thread (Python 3.13 et versions ultérieures)
Dans Python 3.13, une version expérimentale « à threads libres » de CPython a été introduite dans le cadre de la PEP 703 – Rendre le verrou global de l’interpréteur optionnel dans CPython . Cette version permet aux développeurs de compiler Python sans le verrou global de l’interpréteur (GIL), permettant ainsi une véritable exécution parallèle du bytecode Python sur plusieurs cœurs de processeur. Cette fonctionnalité reste expérimentale, mais représente une avancée majeure vers une meilleure gestion de la concurrence dans les futures versions de Python[8].
Voir aussi
[modifier | modifier le code]- Fils verts
- Verrou global du noyau
Références
[modifier | modifier le code]- ↑ « GlobalInterpreterLock », Python Wiki (consulté le )
- ↑ David Beazley, « Inside the Python GIL », Chicago, Chicago Python User Group, (consulté le )
- ↑ Shannon -jj Behrens, « Concurrency and Python », Dr. Dobb's Journal, (consulté le ) : « The GIL is a lock that is used to protect all the critical sections in Python. Hence, even if you have multiple CPUs, only one thread may be doing "pythony" things at a time. », p. 2
- ↑ « Python/C API Reference Manual: Thread State and the Global Interpreter Lock » [archive du ] (consulté le )
- ↑ « IronPython at python.org », python.org (consulté le ) : « IronPython has no GIL and multi-threaded code can use multi core processors. »
- ↑ « HammerDB Concepts and Architecture », HammerDB, (consulté le ) : « It is important to understand at the outset that HammerDB is written in TCL because of the unique threading capabilities that TCL brings. »
- ↑ (en) « threading — Thread-based parallelism », Python documentation (consulté le )
- ↑ (en) « PEP 703 – Making the Global Interpreter Lock Optional in CPython | peps.python.org », Python Enhancement Proposals (PEPs) (consulté le )