web-dev-qa-db-fra.com

Pourquoi était Python écrit avec le GIL?

Le verrouillage de l'interpréteur global (GIL) semble être souvent cité comme une raison majeure pour laquelle le filetage et similaires est une touche délicate dans Python - ce qui soulève la question "Pourquoi cela a-t-il été fait en premier lieu ? "

Étant pas un programmeur, je n'ai aucune idée pourquoi cela pourrait être - quelle était la logique derrière la mise en place du GIL?

122
Fomite

Il existe plusieurs implémentations de Python, par exemple, CPython, IronPython, RPython, etc.

Certains d'entre eux ont un GIL, d'autres non. Par exemple, CPython a le GIL:

De http://en.wikipedia.org/wiki/Global_Interpreter_Lock

Les applications écrites dans des langages de programmation avec un GIL peuvent être conçues pour utiliser des processus séparés pour atteindre un parallélisme complet, car chaque processus a son propre interprète et à son tour a son propre GIL.

Avantages du GIL

  • Augmentation de la vitesse des programmes à thread unique.
  • Intégration facile des bibliothèques C qui ne sont généralement pas thread-safe.

Pourquoi Python (CPython et autres) utilise le GIL

Dans CPython, le verrou d'interpréteur global, ou GIL, est un mutex qui empêche plusieurs threads natifs d'exécuter Python bytecodes à la fois. Ce verrou est nécessaire principalement parce que la gestion de la mémoire de CPython n'est pas sécurisée pour les threads.

Le GIL est controversé car il empêche les programmes CPython multithread de tirer pleinement parti des systèmes multiprocesseurs dans certaines situations. Notez que les opérations potentiellement bloquantes ou de longue durée, telles que les E/S, le traitement d'image et la compression des nombres NumPy, se produisent en dehors du GIL. Ce n'est donc que dans les programmes multithreads qui passent beaucoup de temps à l'intérieur du GIL, interprétant le bytecode CPython, que le GIL devient un goulot d'étranglement.

Python a un GIL par opposition au verrouillage à grain fin pour plusieurs raisons:

  • C'est plus rapide dans le cas d'un seul thread.

  • Il est plus rapide dans le cas multi-thread pour les programmes liés aux E/S.

  • Il est plus rapide dans le cas multi-thread pour les programmes liés au processeur qui effectuent leur travail intensif en calcul dans les bibliothèques C.

  • Cela rend les extensions C plus faciles à écrire: il n'y aura pas de changement de threads Python sauf si vous le permettez (c'est-à-dire entre les macros Py_BEGIN_ALLOW_THREADS et Py_END_ALLOW_THREADS).

  • Il facilite le wrapping des bibliothèques C. Vous n'avez pas à vous soucier de la sécurité des threads. Si la bibliothèque n'est pas thread-safe, vous gardez simplement le GIL verrouillé pendant que vous l'appelez.

Le GIL peut être publié par des extensions C. La bibliothèque standard de Python publie le GIL autour de chaque appel d'E/S bloquant. Ainsi, le GIL n'a aucune conséquence pour les performances des serveurs liés aux E/S. Vous pouvez ainsi créer des serveurs de mise en réseau en Python en utilisant des processus (fork), des threads ou des E/S asynchrones, et le GIL ne vous gênera pas.

Les bibliothèques numériques en C ou en Fortran peuvent également être appelées avec la sortie de GIL. Pendant que votre extension C attend la fin d'une FFT, l'interpréteur exécutera d'autres threads Python. Un GIL est donc plus facile et plus rapide que le verrouillage à grain fin dans ce cas également. Cela constitue la majeure partie du travail numérique. L'extension NumPy libère le GIL autant que possible.

Les threads sont généralement un mauvais moyen d'écrire la plupart des programmes serveur. Si la charge est faible, la fourche est plus facile. Si la charge est élevée, les entrées/sorties asynchrones et la programmation événementielle (par exemple en utilisant le framework Twisted de Python) sont meilleures. La seule excuse pour utiliser des threads est le manque d'os.fork sous Windows.

Le GIL est un problème si, et seulement si, vous effectuez un travail gourmand en CPU en Python pur. Ici, vous pouvez obtenir une conception plus propre à l'aide de processus et de transmission de messages (par exemple, mpi4py). Il y a aussi un module de `` traitement '' dans Python fromagerie, qui donne aux processus la même interface que les threads (c'est-à-dire remplacer threading.Thread par processing.Process).

Les threads peuvent être utilisés pour maintenir la réactivité d'une interface graphique quel que soit le GIL. Si le GIL altère vos performances (cf. la discussion ci-dessus), vous pouvez laisser votre thread générer un processus et attendre qu'il se termine.

110
Md Mahbubur Rahman

Tout d'abord: Python n'a pas de GIL. Python est un langage de programmation. Un langage de programmation est un ensemble de règles et restrictions mathématiques abstraites. Il y a rien dans la spécification de langage Python qui dit qu'il doit y avoir un GIL.

Il existe de nombreuses implémentations différentes de Python. Certains ont un GIL, d'autres non.

Une explication simple pour avoir un GIL est que l'écriture de code simultané est difficile. En plaçant un verrou géant autour de votre code, vous le forcez à toujours s'exécuter en série. Problème résolu!

En CPython, en particulier, un objectif important est de faciliter l'extension de l'interpréteur avec des plugins écrits en C. Encore une fois, l'écriture de code simultané est difficile, donc en garantissant qu'il n'y aura pas de concurrence, il est plus facile d'écrire des extensions pour l'interprète. De plus, bon nombre de ces extensions ne sont que des enveloppes minces autour des bibliothèques existantes qui n'ont peut-être pas été écrites avec la simultanéité à l'esprit.

42
Jörg W Mittag

Quel est le but d'un GIL?

La documentation de l'ICPA a ceci à dire sur le sujet:

L'interpréteur Python n'est pas entièrement thread-safe. Afin de prendre en charge les programmes multi-thread Python, il existe un verrou global, appelé verrou interprète global ou GIL , qui doit être détenu par le thread actuel avant qu'il ne puisse 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émenter simultanément le compte de référence du même objet, le compte de référence pourrait finir par être incrémenté une seule fois au lieu de deux.

En d'autres termes, le GIL empêche la corruption de l'État. Python ne doivent jamais produire d'erreur de segmentation, car seules les opérations sécurisées en mémoire sont autorisées. Le GIL étend cette assurance aux programmes multithreads.

Quelles sont les alternatives?

Si le but du GIL est de protéger l'État contre la corruption, alors une alternative évidente est de verrouiller à un grain beaucoup plus fin; peut-être au niveau de chaque objet. Le problème avec cela est que bien qu'il ait été démontré qu'il augmente les performances des programmes multithread, il en résulte plus de surcharge et les programmes monothread en souffrent.

17
dan_waterworth