Comment fonctionnent les threads en Python et quels sont les pièges courants spécifiques au thread Python ?

StackOverflow https://stackoverflow.com/questions/31340

  •  09-06-2019
  •  | 
  •  

Question

J'ai essayé de comprendre comment fonctionnent les threads en Python, et il est difficile de trouver de bonnes informations sur leur fonctionnement.Il me manque peut-être simplement un lien ou quelque chose du genre, mais il semble que la documentation officielle ne soit pas très complète sur le sujet et je n'ai pas réussi à trouver un bon article.

D'après ce que je peux dire, un seul thread peut être exécuté à la fois et le thread actif change toutes les 10 instructions environ ?

Où y a-t-il une bonne explication, ou pouvez-vous en fournir une ?Ce serait également très bien d'être conscient des problèmes courants que vous rencontrez lors de l'utilisation de threads avec Python.

Était-ce utile?

La solution

Oui, en raison du Global Interpreter Lock (GIL), il ne peut exécuter qu'un seul thread à la fois.Voici quelques liens avec quelques informations à ce sujet :

Du dernier lien, une citation intéressante :

Laissez-moi vous expliquer ce que tout cela signifie.Les threads fonctionnent à l'intérieur de la même machine virtuelle et fonctionnent donc sur la même machine physique.Les processus peuvent fonctionner sur la même machine physique ou dans une autre machine physique.Si vous architectez votre application autour des threads, vous n'avez rien fait pour accéder à plusieurs machines.Ainsi, vous pouvez évoluer à autant de noyaux sur la machine unique (qui en sera un peu au fil du temps), mais pour vraiment atteindre les échelles Web, vous devrez quand même résoudre le problème de la machine à plusieurs fois.

Si vous souhaitez utiliser le multicœur, traitement py définit une API basée sur un processus pour effectuer une véritable parallélisation.Le DYNAMISME comprend également quelques repères intéressants.

Autres conseils

Python est un langage assez simple à utiliser, mais il existe des mises en garde.La chose la plus importante que vous devez savoir est le Global Interpreter Lock.Cela permet à un seul thread d'accéder à l'interpréteur.Cela signifie deux choses :1) vous vous retrouvez rarement à utiliser une instruction lock en python et 2) si vous souhaitez profiter des systèmes multiprocesseurs, vous devez utiliser des processus distincts.MODIFIER:Je dois également souligner que vous pouvez mettre une partie du code en C/C++ si vous souhaitez également contourner le GIL.

Ainsi, vous devez reconsidérer pourquoi vous souhaitez utiliser les threads.Si vous souhaitez paralléliser votre application pour tirer parti de l'architecture dual-core, vous devez envisager de diviser votre application en plusieurs processus.

Si vous souhaitez améliorer la réactivité, vous devriez CONSIDÉRER l'utilisation de threads.Il existe cependant d'autres alternatives, à savoir microfilage.Il existe également certains frameworks que vous devriez examiner :

Vous trouverez ci-dessous un exemple de thread de base.Cela générera 20 threads ;chaque thread affichera son numéro de thread.Exécutez-le et observez l’ordre dans lequel ils s’impriment.

import threading
class Foo (threading.Thread):
    def __init__(self,x):
        self.__x = x
        threading.Thread.__init__(self)
    def run (self):
          print str(self.__x)

for x in xrange(20):
    Foo(x).start()

Comme vous l'avez laissé entendre, les threads Python sont implémentés via un découpage temporel.C'est ainsi qu'ils obtiennent l'effet « parallèle ».

Dans mon exemple, ma classe Foo étend le thread, j'implémente ensuite le run méthode, qui est l'endroit où va le code que vous souhaitez exécuter dans un thread.Pour démarrer le fil de discussion que vous appelez start() sur l'objet thread, qui invoquera automatiquement le run méthode...

Bien sûr, ce ne sont que les bases.Vous souhaiterez éventuellement en savoir plus sur les sémaphores, les mutex et les verrous pour la synchronisation des threads et la transmission des messages.

Utilisez des threads en python si les travailleurs individuels effectuent des opérations liées aux E/S.Si vous essayez d'évoluer sur plusieurs cœurs sur une machine, trouvez un bon CIB framework pour python ou choisissez un autre langage.

Note: partout où je mentionne thread je veux dire spécifiquement fils de discussion en python jusqu'à ce qu'il soit explicitement indiqué.

Les threads fonctionnent un peu différemment en python si vous venez de C/C++ arrière-plan.En python, un seul thread peut être en cours d'exécution à un moment donné. Cela signifie que les threads en python ne peuvent pas véritablement exploiter la puissance de plusieurs cœurs de traitement puisque, de par leur conception, il n'est pas possible pour les threads de s'exécuter en parallèle sur plusieurs cœurs.

Comme la gestion de la mémoire en Python n'est pas thread-safe, chaque thread nécessite un accès exclusif aux structures de données dans l'interpréteur Python. Cet accès exclusif est acquis par un mécanisme appelé GIL (verrouillage global de l'interprète).

Why does python use GIL?

Afin d'empêcher plusieurs threads d'accéder simultanément à l'état de l'interprète et de corrompre l'état de l'interprète.

L'idée est qu'à chaque fois qu'un thread est en cours d'exécution (même si c'est le fil principal), un GIL est acquis et après un intervalle de temps prédéfini, le GIL est libéré par le thread actuel et réagi par un autre thread (le cas échéant).

Why not simply remove GIL?

Ce n'est pas qu'il est impossible de supprimer GIL, c'est juste que ce faisant, nous finissons par placer plusieurs verrous dans l'interpréteur afin de sérialiser l'accès, ce qui rend même une application à un seul thread moins performante.

Ainsi, le coût de la suppression de GIL est compensé par la réduction des performances d'une application à thread unique, ce qui n'est jamais souhaité.

So when does thread switching occurs in python?

Le changement de thread se produit lorsque GIL est publié. Alors, quand GIL est-il publié ?Il y a deux scénarios à prendre en considération.

Si un thread effectue des opérations liées au CPU (ex. traitement d'image).

Dans les anciennes versions de Python, le changement de thread se produisait après un nombre fixe d'instructions Python. Il était défini par défaut sur 100. Il s'est avéré que ce n'est pas une très bonne politique pour décider quand le changement devrait se produire car le temps passé à exécuter une seule instruction peut très sauvagement de la milliseconde à même une seconde. 100 les instructions, quel que soit le temps nécessaire à leur exécution, constituent une mauvaise politique.

Dans les nouvelles versions, au lieu d'utiliser le nombre d'instructions comme métrique pour changer de thread, un intervalle de temps configurable est utilisé.L'intervalle de commutation par défaut est de 5 millisecondes. Vous pouvez obtenir l'intervalle de commutation actuel en utilisant sys.getswitchinterval().Ceci peut être modifié en utilisant sys.setswitchinterval()

Si un thread effectue des opérations liées aux IO (accès au système de fichiers Ex ou
réseau IO)

GIL est publié chaque fois que le thread attend la fin de l'opération IO.

Which thread to switch to next?

L’interpréteur n’a pas son propre planificateur. Le choix du thread qui sera planifié à la fin de l’intervalle relève du système d’exploitation..

Une solution simple au GIL est la multitraitement module.Il peut être utilisé en remplacement du module de threading, mais utilise plusieurs processus Interpreter au lieu de threads.Pour cette raison, il y a un peu plus de surcharge que le simple threading pour des choses simples, mais cela vous donne l'avantage d'une véritable parallélisation si vous en avez besoin.Il s’adapte également facilement à plusieurs machines physiques.

Si vous avez besoin d'une parallélisation à très grande échelle, je chercherais plus loin, mais si vous souhaitez simplement évoluer vers tous les cœurs d'un ordinateur ou quelques cœurs différents sans tout le travail nécessaire à la mise en œuvre d'un cadre plus complet, alors ceci est pour vous. .

Essayez de vous rappeler que le GIL est configuré pour interroger de temps en temps afin de montrer l'apparence de plusieurs tâches.Ce paramètre peut être ajusté, mais je suggère que les threads devraient effectuer du travail, sinon de nombreux changements de contexte vont causer des problèmes.

J'irais jusqu'à suggérer plusieurs parents sur les processeurs et essayer de conserver des emplois similaires sur le(s) même(s) noyau(s).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top