Pourquoi le Global Interpreter Lock?


89

Quelle est exactement la fonction de Global Interpreter Lock de Python? Les autres langages compilés en bytecode utilisent-ils un mécanisme similaire?


6
Vous devriez également demander "Est-ce que c'est important?"
S.Lott

2
Je suis d'accord, je considère que c'est un non-problème maintenant que dans la version 2.6, le module multiprocesseur a été ajouté pour vous permettre de programmer en utilisant plusieurs processus à la manière d'un thread. docs.python.org/library/multiprocessing.html
monkut

Réponses:


69

En général, pour tout problème de sécurité des threads, vous devrez protéger vos structures de données internes avec des verrous. Cela peut être fait avec différents niveaux de granularité.

  • Vous pouvez utiliser un verrouillage à grain fin, où chaque structure séparée a son propre verrou.

  • Vous pouvez utiliser un verrouillage à gros grains où un verrou protège tout (l'approche GIL).

Il existe différents avantages et inconvénients de chaque méthode. Le verrouillage fin permet un plus grand parallélisme - deux threads peuvent s'exécuter en parallèle lorsqu'ils ne partagent aucune ressource. Cependant, les frais généraux administratifs sont beaucoup plus importants. Pour chaque ligne de code, vous devrez peut-être acquérir et libérer plusieurs verrous.

L'approche à gros grains est le contraire. Deux threads ne peuvent pas s'exécuter en même temps, mais un thread individuel s'exécutera plus rapidement car il ne fait pas tellement de comptabilité. En fin de compte, cela revient à un compromis entre la vitesse à un seul thread et le parallélisme.

Il y a eu quelques tentatives pour supprimer le GIL en python, mais la surcharge supplémentaire pour les machines à thread unique était généralement trop importante. Certains cas peuvent en fait être plus lents même sur des machines multiprocesseurs en raison d'un conflit de verrouillage.

Les autres langages compilés en bytecode utilisent-ils un mécanisme similaire?

Cela varie et il ne devrait probablement pas être considéré comme une propriété de langage autant qu'une propriété d'implémentation. Par exemple, il existe des implémentations Python telles que Jython et IronPython qui utilisent l'approche threading de leur VM sous-jacente, plutôt qu'une approche GIL. De plus, la prochaine version de Ruby semble s'orienter vers l' introduction d'un GIL.


1
pouvez-vous expliquer ceci: "Deux threads ne peuvent pas fonctionner en même temps"? Récemment, j'ai écrit un simple serveur Web en Python avec multithreading. Pour chaque nouvelle demande du client, les serveurs génèrent un nouveau thread pour lui et ces threads continuent de s'exécuter. Il y aura donc plusieurs threads en cours d'exécution en même temps, n'est-ce pas? Ou ai-je mal compris?
avi

1
Les threads python @avi AFAIK ne peuvent pas s'exécuter simultanément, mais cela ne signifie pas qu'un thread doit bloquer l'autre. GIL signifie seulement qu'un seul thread peut interpréter le code Python à la fois, cela ne signifie pas que la gestion des threads et l'allocation des ressources ne fonctionnent pas.
Benproductions1

2
^ donc à tout moment, un seul thread servira du contenu au client ... donc inutile d'utiliser le multithreading pour améliorer les performances. droite?
avi

Et, bien sûr, Java est compilé en byte code et permet un verrouillage très fin.
Warren Dew

3
@avi, un processus lié aux E / S comme un serveur Web peut toujours bénéficier des threads Python. Deux threads ou plus peuvent effectuer des E / S simultanément. Ils ne peuvent tout simplement pas être interprétés (CPU) simultanément.
Saish

33

Ce qui suit est extrait du manuel de référence officiel de l'API Python / C :

L'interpréteur Python n'est pas entièrement thread-safe. Afin de prendre en charge les programmes Python multithreads, il existe un verrou global qui doit être détenu par le thread actuel avant de pouvoir accéder en toute sécurité aux objets Python. Sans le verrou, même les opérations les plus simples pourraient causer des problèmes dans un programme multi-thread: par exemple, lorsque deux threads incrémentent simultanément le nombre de références du même objet, le nombre de références pourrait finir par être incrémenté une seule fois au lieu de deux.

Par conséquent, il existe une règle selon laquelle seul le thread qui a acquis le verrou d'interpréteur global peut fonctionner sur des objets Python ou appeler des fonctions API Python / C. Afin de prendre en charge les programmes Python multi-threads, l'interpréteur libère et réacquiert régulièrement le verrou - par défaut, toutes les 100 instructions de bytecode (cela peut être changé avec sys.setcheckinterval ()). Le verrou est également libéré et réacquis autour des opérations d'E / S potentiellement bloquantes comme la lecture ou l'écriture d'un fichier, de sorte que d'autres threads puissent s'exécuter pendant que le thread qui demande les E / S attend la fin de l'opération d'E / S.

Je pense que cela résume assez bien le problème.


1
Je l'ai lu aussi, mais je ne comprends pas pourquoi Python est différent à cet égard de, disons, java (est-ce?)
Federico A. Ramponi

Les threads @EliBendersky Python sont implémentés en tant que pthreads et sont gérés par le système d'exploitation ( dabeaz.com/python/UnderstandingGIL.pdf ) tandis que les threads Java sont des threads de niveau application dont la planification est gérée par la JVM
gokul_uf

19

Le verrou d'interprétation global est un gros verrou de type mutex qui empêche les compteurs de référence d'être arrosés. Si vous écrivez du code python pur, tout se passe dans les coulisses, mais si vous intégrez Python dans C, vous devrez peut-être explicitement prendre / libérer le verrou.

Ce mécanisme n'est pas lié à la compilation de Python en bytecode. Ce n'est pas nécessaire pour Java. En fait, ce n'est même pas nécessaire pour Jython (python compilé en jvm).

voir aussi cette question


4
«Ce mécanisme n'est pas lié au fait que Python est compilé en bytecode»: précisément, c'est un artefact de l'implémentation CPython. D'autres implémentations (comme Jython que vous avez mentionnées) peuvent être exemptes de cette restriction en raison de leur implémentation thread-safe
Eli Bendersky

11

Python, comme perl 5, n'a pas été conçu dès le départ pour être thread-safe. Les threads ont été greffés après coup, donc le verrou d'interprétation global est utilisé pour maintenir l'exclusion mutuelle là où un seul thread exécute du code à un moment donné dans les entrailles de l'interpréteur.

Les threads Python individuels sont multitâches de manière coopérative par l'interpréteur lui-même en effectuant un cycle de verrouillage de temps en temps.

Il est nécessaire de saisir le verrou vous-même lorsque vous parlez à Python à partir de C lorsque d'autres threads Python sont actifs pour `` accepter '' ce protocole et vous assurer que rien de dangereux ne se produit dans votre dos.

D'autres systèmes qui ont un héritage à un seul thread qui ont ensuite évolué vers des systèmes multi-threadés ont souvent un mécanisme de ce type. Par exemple, le noyau Linux a le "Big Kernel Lock" de ses débuts SMP. Au fil du temps, au fur et à mesure que les performances multi-threading deviennent un problème, il y a une tendance à essayer de briser ces types de verrous en plus petits morceaux ou de les remplacer par des algorithmes et des structures de données sans verrouillage lorsque cela est possible pour maximiser le débit.


+1 pour avoir mentionné le fait que le verrouillage à gros grains est utilisé que la plupart des gens le pensent, en particulier le BKL souvent oublié (j'utilise reiserfs- la seule vraie raison pour laquelle je le connais).
nouveau123456

3
Linux avait BKL, depuis la version 2.6.39, BKL a été complètement supprimé.
avi

5
Bien sûr. Rappelez-vous que c'était ~ 3 ans après avoir répondu à la question. =)
Edward KMETT

7

En ce qui concerne votre deuxième question, tous les langages de script ne l'utilisent pas, mais cela ne fait que les rendre moins puissants. Par exemple, les threads de Ruby sont verts et non natifs.

En Python, les threads sont natifs et le GIL les empêche uniquement de s'exécuter sur des cœurs différents.

En Perl, les threads sont encore pires. Ils ne font que copier l'intégralité de l'interpréteur, et sont loin d'être aussi utilisables qu'en Python.


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.