J'essaie de comprendre le filetage en Python. J'ai regardé la documentation et les exemples, mais franchement, de nombreux exemples sont trop sophistiqués et j'ai du mal à les comprendre.
Comment montrez-vous clairement que les tâches sont divisées pour le multithread?
Réponses:
Depuis que cette question a été posée en 2010, il y a eu une réelle simplification dans la façon de faire du multithreading simple avec Python avec carte et pool .
Le code ci-dessous provient d'un article / blog que vous devriez absolument vérifier (pas d'affiliation) - Parallélisme en une seule ligne: un meilleur modèle pour les tâches de threading quotidiennes . Je vais résumer ci-dessous - cela finit par n'être que quelques lignes de code:
Quelle est la version multithread de:
La description
la mise en oeuvre
multiprocessing.dummy
est exactement le même que le module multiprocessing, mais utilise des threads à la place ( une distinction importante - utilisez plusieurs processus pour les tâches gourmandes en CPU; threads pour (et pendant) les E / S ):Et les résultats du timing:
Passer plusieurs arguments (fonctionne comme ça uniquement dans Python 3.3 et versions ultérieures ):
Pour passer plusieurs tableaux:
Ou pour passer une constante et un tableau:
Si vous utilisez une version antérieure de Python, vous pouvez passer plusieurs arguments via cette solution de contournement ).
(Merci à user136036 pour le commentaire utile.)
la source
with Pool(8) as p: p.map( *whatever* )
et vous débarrasser des lignes de comptabilité.Voici un exemple simple: vous devez essayer quelques URL alternatives et renvoyer le contenu de la première à répondre.
C'est un cas où le threading est utilisé comme une simple optimisation: chaque sous-thread attend une URL pour résoudre et répondre, afin de mettre son contenu dans la file d'attente; chaque thread est un démon (ne poursuivra pas le processus si le thread principal se termine - c'est plus courant qu'improbable); le thread principal démarre tous les sous-threads, fait un
get
sur la file d'attente pour attendre que l'un d'eux ait fait unput
, puis émet les résultats et se termine (ce qui supprime tous les sous-threads qui pourraient encore être en cours d'exécution, car ce sont des threads démon).L'utilisation correcte des threads en Python est invariablement connectée aux opérations d'E / S (puisque CPython n'utilise pas plusieurs cœurs pour exécuter les tâches liées au CPU de toute façon, la seule raison du threading n'est pas de bloquer le processus pendant qu'il y a une attente pour certaines E / S ). Les files d'attente sont presque toujours le meilleur moyen de regrouper le travail en threads et / ou de collecter les résultats du travail, en passant, et elles sont intrinsèquement threadsafe, de sorte qu'elles vous évitent de vous soucier des verrous, des conditions, des événements, des sémaphores et d'autres inter -filer les concepts de coordination / communication.
la source
join()
méthode, car cela ferait attendre le thread principal jusqu'à ce qu'ils soient terminés sans consommer le processeur en permanence vérification de la valeur. @Alex: merci, c'est exactement ce dont j'avais besoin pour comprendre comment utiliser les threads.Queue
nom du module parqueue
. Le nom de la méthode est le même.s = q.get()
print s
@ krs013 Vous n'avez pas besoin dujoin
car Queue.get () bloque.REMARQUE : pour la parallélisation réelle en Python, vous devez utiliser le module de multitraitement pour bifurquer plusieurs processus qui s'exécutent en parallèle (en raison du verrouillage de l'interpréteur global, les threads Python fournissent l'entrelacement, mais ils sont en fait exécutés en série, pas en parallèle, et ne sont que utile lors de l'entrelacement d'opérations d'E / S).
Cependant, si vous recherchez simplement un entrelacement (ou effectuez des opérations d'E / S qui peuvent être parallélisées malgré le verrouillage de l'interpréteur global), le module de thread est le point de départ. Comme exemple très simple, considérons le problème de la sommation d'une large plage en sommant les sous-plages en parallèle:
Notez que ce qui précède est un exemple très stupide, car il ne fait absolument aucune E / S et sera exécuté en série bien qu'entrelacé (avec la surcharge supplémentaire de changement de contexte) dans CPython en raison du verrouillage de l'interpréteur global.
la source
thread1
s'exécute jusqu'à ce qu'il soit terminé pendant que le thread principal se bloque, puis la même chose se produitthread2
, puis le thread principal reprend et imprime les valeurs accumulées.super(SummingThread, self).__init__()
? Comme dans stackoverflow.com/a/2197625/806988Comme d'autres l'ont mentionné, CPython peut utiliser des threads uniquement pour les attentes d'E / S en raison de GIL .
Si vous souhaitez bénéficier de plusieurs cœurs pour les tâches liées au processeur, utilisez le multitraitement :
la source
f
fonction. En parallèle, le programme principal n'attend plus que la fin du processus pour l'join
intégrer. Si la partie principale vient de sortir, le sous-processus peut ou non s'exécuter jusqu'à la fin, iljoin
est donc recommandé de faire un .map
fonction est ici: stackoverflow.com/a/28463266/2327328Juste une note: une file d'attente n'est pas requise pour le filetage.
Ceci est l'exemple le plus simple que je pourrais imaginer qui montre 10 processus s'exécutant simultanément.
la source
for
boucle, vous pouvez appelerthread.start()
en première boucle.La réponse d'Alex Martelli m'a aidé. Cependant, voici une version modifiée que je pensais plus utile (au moins pour moi).
Mise à jour: fonctionne à la fois en Python 2 et Python 3
la source
import Queue ModuleNotFoundError: No module named 'Queue'
j'utilise python 3.6.5 certains articles mentionnent qu'en python 3.6.5 c'est le casqueue
mais même après l'avoir changé, cela ne fonctionne toujours pasÉtant donné une fonction
f
,, enfilez-la comme ceci:Pour passer des arguments à
f
la source
Thread
objet est nettoyé. Voir les documents . Il existe uneis_alive()
méthode que vous pouvez utiliser pour vérifier un thread si vous en avez besoin.is_alive
méthode, mais je n'ai pas pu comprendre comment l'appliquer au fil. J'ai essayé d'affecterthread1=threading.Thread(target=f).start()
puis de vérifier avecthread1.is_alive()
, maisthread1
est rempliNone
, donc pas de chance là-bas. Savez-vous s'il existe un autre moyen d'accéder au fil?thread1=threading.Thread(target=f)
suivie dethread1.start()
. Ensuite, vous pouvez le fairethread1.is_alive()
.thread1.is_alive()
retoursFalse
dès que la fonction se termine.J'ai trouvé cela très utile: créez autant de threads que de cœurs et laissez-les exécuter un (grand) nombre de tâches (dans ce cas, appeler un programme shell):
la source
Python 3 a la possibilité de lancer des tâches parallèles . Cela facilite notre travail.
Il a un pool de threads et un pool de processus .
Ce qui suit donne un aperçu:
Exemple ThreadPoolExecutor ( source )
ProcessPoolExecutor ( source )
la source
Utilisation du nouveau module concurrent.futures flamboyant
L'approche de l'exécuteur peut sembler familière à tous ceux qui se sont déjà salis les mains avec Java auparavant.
Également sur une note secondaire: pour garder l'univers sain d'esprit, n'oubliez pas de fermer vos pools / exécuteurs si vous n'utilisez pas le
with
contexte (ce qui est tellement génial qu'il le fait pour vous)la source
Pour moi, l'exemple parfait pour le filetage est la surveillance des événements asynchrones. Regardez ce code.
Vous pouvez jouer avec ce code en ouvrant une session IPython et en faisant quelque chose comme:
Attends quelques minutes
la source
La plupart de la documentation et des didacticiels utilisent Python
Threading
et leQueue
module, et ils peuvent sembler écrasants pour les débutants.Considérons peut-être le
concurrent.futures.ThreadPoolExecutor
module de Python 3.Combiné avec la
with
compréhension des clauses et des listes, cela pourrait être un vrai charme.la source
J'ai vu beaucoup d'exemples ici où aucun travail réel n'était effectué, et ils étaient principalement liés au processeur. Voici un exemple de tâche liée au processeur qui calcule tous les nombres premiers entre 10 millions et 10,05 millions. J'ai utilisé les quatre méthodes ici:
Voici les résultats sur ma machine à quatre cœurs Mac OS X
la source
if __name__ == '__main__':
avant l'appel principal, sinon les pontes de mesure lui - même et imprime une tentative a été faite pour commencer un nouveau processus avant ... .Voici l'exemple très simple de l' importation CSV en utilisant le filetage. (L'inclusion dans la bibliothèque peut différer pour différents objectifs.)
Fonctions d'assistance:
Fonction pilote:
la source
Je voudrais contribuer avec un exemple simple et les explications que j'ai trouvées utiles lorsque j'ai dû résoudre ce problème moi-même.
Dans cette réponse, vous trouverez des informations sur le GIL de Python (verrouillage de l'interpréteur global) et un exemple simple écrit au jour le jour à l'aide de multiprocessing.dummy ainsi que quelques tests de référence simples.
Verrou d'interprète global (GIL)
Python n'autorise pas le multi-threading dans le vrai sens du mot. Il a un package multi-thread, mais si vous voulez multi-thread pour accélérer votre code, ce n'est généralement pas une bonne idée de l'utiliser.
Python a une construction appelée le verrou d'interpréteur global (GIL). Le GIL s'assure qu'un seul de vos «threads» peut s'exécuter à la fois. Un thread acquiert le GIL, fait un petit travail, puis passe le GIL sur le thread suivant.
Cela se produit très rapidement, donc à l'œil humain, il peut sembler que vos threads s'exécutent en parallèle, mais ils se tournent vraiment à tour de rôle en utilisant le même cœur de processeur.
Tout ce passage GIL ajoute des frais généraux à l'exécution. Cela signifie que si vous souhaitez accélérer l'exécution de votre code, l'utilisation du package de thread n'est souvent pas une bonne idée.
Il y a des raisons d'utiliser le package de threads de Python. Si vous voulez exécuter certaines choses simultanément et que l'efficacité n'est pas un problème, c'est tout à fait correct et pratique. Ou si vous exécutez du code qui doit attendre quelque chose (comme des E / S), cela peut avoir beaucoup de sens. Mais la bibliothèque de threads ne vous permettra pas d'utiliser des cœurs de processeur supplémentaires.
Le multi-threading peut être externalisé vers le système d'exploitation (en effectuant le multi-traitement) et une application externe qui appelle votre code Python (par exemple, Spark ou Hadoop ), ou du code que votre code Python appelle (par exemple: vous pourriez demandez à votre code Python d'appeler une fonction C qui fait les choses coûteuses multi-thread).
Pourquoi c'est important
Parce que beaucoup de gens passent beaucoup de temps à essayer de trouver des goulots d'étranglement dans leur code multi-thread Python avant d'apprendre ce qu'est le GIL.
Une fois ces informations claires, voici mon code:
la source
Voici le multi threading avec un exemple simple qui vous sera utile. Vous pouvez l'exécuter et comprendre facilement le fonctionnement du multi-threading en Python. J'ai utilisé un verrou pour empêcher l'accès aux autres threads jusqu'à ce que les threads précédents aient terminé leur travail. Par l'utilisation de cette ligne de code,
vous pouvez autoriser un certain nombre de processus à la fois et conserver le reste des threads qui s'exécuteront plus tard ou après la fin des processus précédents.
la source
En empruntant à ce poste, nous savons comment choisir entre le multithreading, le multiprocessing et l'async /
asyncio
et leur utilisation.Python 3 a une nouvelle bibliothèque intégrée pour concurrencer et paralléliser: concurrent.futures
Je vais donc démontrer à travers une expérience pour exécuter quatre tâches (c'est-à-dire la
.sleep()
méthode) deThreading-Pool
manière:Production:
[ REMARQUE ]:
multiprocessing
vsthreading
), vous pouvez changer laThreadPoolExecutor
enProcessPoolExecutor
.la source
Aucune des solutions précédentes n'utilisait réellement plusieurs cœurs sur mon serveur GNU / Linux (où je n'ai pas de droits d'administrateur). Ils ont simplement fonctionné sur un seul cœur.
J'ai utilisé l'
os.fork
interface de niveau inférieur pour générer plusieurs processus. Voici le code qui a fonctionné pour moi:la source
la source