Documentation Python 3.7
Je voudrais également souligner la citation suivante de la documentation Pythonthreading
:
Détail de l'implémentation de CPython: dans CPython, en raison du verrouillage de l'interpréteur global, un seul thread peut exécuter du code Python à la fois (même si certaines bibliothèques axées sur les performances peuvent surmonter cette limitation). Si vous souhaitez que votre application utilise mieux les ressources de calcul des machines multicœurs, il est conseillé d'utiliser multiprocessing
ou concurrent.futures.ProcessPoolExecutor
. Cependant, le thread est toujours un modèle approprié si vous souhaitez exécuter simultanément plusieurs tâches liées aux E / S.
Ce lien renvoie à l' entréeglobal interpreter lock
du glossaire qui explique que le GIL implique que le parallélisme fileté en Python ne convient pas aux tâches liées au processeur :
Le mécanisme utilisé par l'interpréteur CPython pour garantir qu'un seul thread exécute le bytecode Python à la fois. Cela simplifie l'implémentation de CPython en rendant le modèle d'objet (y compris les types intégrés critiques tels que dict) protégé implicitement contre les accès simultanés. Le verrouillage de l'intégralité de l'interpréteur facilite le multithread pour l'interpréteur, au détriment d'une grande partie du parallélisme offert par les machines multiprocesseurs.
Cependant, certains modules d'extension, standard ou tiers, sont conçus pour libérer le GIL lors de l'exécution de tâches à forte intensité de calcul telles que la compression ou le hachage. De plus, le GIL est toujours libéré lors des E / S.
Les efforts antérieurs pour créer un interpréteur «libre» (celui qui verrouille les données partagées à une granularité beaucoup plus fine) n'ont pas été couronnés de succès car les performances ont souffert dans le cas d'un seul processeur commun. On pense que surmonter ce problème de performance rendrait la mise en œuvre beaucoup plus compliquée et donc plus coûteuse à maintenir.
Cette citation implique également que les dicts et donc l'affectation des variables sont également thread-safe en tant que détail d'implémentation CPython:
Ensuite, les documents du multiprocessing
package expliquent comment il surmonte le GIL en générant un processus tout en exposant une interface similaire à celle de threading
:
le multiprocessing est un package qui prend en charge les processus de génération à l'aide d'une API similaire au module de thread. Le package de multitraitement offre une concurrence à la fois locale et distante, évitant efficacement le verrouillage d'interpréteur global en utilisant des sous-processus au lieu de threads. Pour cette raison, le module multiprocesseur permet au programmeur de tirer pleinement parti de plusieurs processeurs sur une machine donnée. Il fonctionne sur Unix et Windows.
Et les documentsconcurrent.futures.ProcessPoolExecutor
expliquent qu'il utilise multiprocessing
comme backend:
La classe ProcessPoolExecutor est une sous-classe Executor qui utilise un pool de processus pour exécuter des appels de manière asynchrone. ProcessPoolExecutor utilise le module de multitraitement, ce qui lui permet de contourner le verrou d'interpréteur global, mais signifie également que seuls les objets picklables peuvent être exécutés et renvoyés.
qui devrait être contrasté avec l'autre classe de base ThreadPoolExecutor
qui utilise des threads au lieu de processus
ThreadPoolExecutor est une sous-classe Executor qui utilise un pool de threads pour exécuter des appels de manière asynchrone.
d'où nous concluons qu'il ThreadPoolExecutor
ne convient qu'aux tâches liées aux E / S, tout en ProcessPoolExecutor
pouvant également gérer les tâches liées au processeur.
La question suivante demande pourquoi le GIL existe en premier lieu: pourquoi le verrouillage d'interprète global?
Expériences processus vs thread
Chez Multiprocessing vs Threading Python, j'ai fait une analyse expérimentale des processus vs threads en Python.
Aperçu rapide des résultats: