web-dev-qa-db-fra.com

Pourquoi le Global Interpreter Lock?

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

86

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 distincte a son propre verrou.

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

Il existe différents avantages et inconvénients de chaque méthode. Le verrouillage à grain 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 à grain grossier 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 beaucoup de comptabilité. En fin de compte, cela se résume à un compromis entre la vitesse d'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.

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

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

69
Brian

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

L'interpréteur Python n'est pas entièrement sûr pour les threads. Afin de prendre en charge les programmes multi-thread Python, il y a un verrou global qui doit être maintenu par le thread actuel avant il peut accéder en toute sécurité aux objets Python. Sans le verrou, même les opérations les plus simples pourraient provoquer des problèmes dans un programme multithread: par exemple, lorsque deux threads incrémentent simultanément le nombre de références du même objet, le compte de référence 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 plusieurs threads Python, l'interprète 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 ()). des opérations telles que la lecture ou l'écriture d'un fichier, afin 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.

33
Eli Bendersky

Le verrou d'interpréteur global est un gros verrou de type mutex qui protège les compteurs de référence contre tout arrosage. Si vous écrivez du code python pur, tout cela se passe dans les coulisses, mais si vous intégrez Python dans C, alors vous devrez peut-être explicitement prendre/relâcher) le verrou.

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

voir aussi cette question

19
David Nehme

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, de sorte que le verrou d'interpréteur 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.

Individuels Python sont multitâches en coopération par l'interpréteur lui-même en cyclant le verrou de temps en temps.

Saisir le verrou vous-même est nécessaire lorsque vous parlez à Python de C lorsque d'autres threads Python threads sont actifs pour `` adhérer '' à ce protocole et assurez-vous que rien de dangereux ne se passe derrière votre dos.

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

11
Edward KMETT

Concernant votre deuxième question, tous les langages de script ne l'utilisent pas, mais cela les rend seulement moins puissants. Par exemple, les threads de Ruby sont verts et non natifs.

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

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

7
Eli Bendersky

Peut-être que cet article du BDFL vous aidera.

2
Jeremy Cantrell