Quelle est exactement la fonction de Global Interpreter Lock de Python? Les autres langages compilés en bytecode utilisent-ils un mécanisme similaire?
Quelle est exactement la fonction de Global Interpreter Lock de Python? Les autres langages compilés en bytecode utilisent-ils un mécanisme similaire?
Réponses:
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.
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.
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
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.
reiserfs
- la seule vraie raison pour laquelle je le connais).
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.