122 votes

choisir entre sous-processus, multitraitement et thread en Python?

Je tiens à paralléliser mon programme Python de sorte qu'il peut utiliser plusieurs processeurs de la machine sur lequel il s'exécute. Mon parallélisation est très simple, en ce que tous les parallèles "fils" du programme sont indépendants et écrire leur sortie, dans des fichiers séparés. Je n'ai pas besoin de threads pour l'échange d'informations, mais il est impératif que je sais que lorsque le fils de course depuis quelques étapes de mon pipeline dépendent de leur sortie.

La portabilité est importante, et que j'aimerais que ce à exécuter sur n'importe quel version de Python sur Mac, Linux et Windows. Compte tenu de ces contraintes, ce qui est le plus approprié module Python pour sa mise en œuvre? Je suis en train de décider entre thread, sous-processus et le multitraitement, qui semblent tous liés à la fonctionnalité.

Des idées sur ce point? J'aimerais que la solution la plus simple c'est portable.

Merci.

203voto

Jim Dennis Points 5454

Pour moi, c'est en fait assez simple:

subprocess est pour l'exécution d'autres exécutables --- en gros, c'est un wrapper autour de os.fork() et os.execve() , avec un certain soutien pour l'option de plomberie (installation de Tuyaux et de la sous-processus. (Évidemment, d'autres systèmes de communication inter-processus (IPC) des mécanismes, tels que les sockets, SysV de la mémoire partagée et les files d'attente peuvent être utilisés --- mais en général, vous êtes à l'aide de sous-processus à exécuter tiers exécutables binaires et vont être coincé avec les interfaces et les canaux IPC ceux à l'appui).

Généralement on utilise subprocess de façon synchrone --- il suffit d'appeler certains utilitaire externe et de la lecture du son en sortie ou en attente de sa réalisation (peut-être la lecture de ses résultats à partir d'un fichier temporaire, ou après affichée sur son site à une base de données). Cependant, on peut pondre des centaines de sous-processus et de sondage. Mon propre favori utilitaire est exactement ce que fait. Le plus grand inconvénient de l' subprocess module, c'est que son support e/S est généralement de blocage. Il y a le projet PEP-3145 le corriger dans une version future de Python 3.x et une alternative asyncproc (Avertissement qui mène droit à la télécharger, et non à toute sorte de documentation, ni README). J'ai trouvé aussi qu'il est relativement facile de simplement importer fcntl et de manipuler votre Popen PIPE descripteurs de fichiers directement --- si je ne sais pas si c'est portable pour non-plates-formes UNIX.

subprocess a presque pas de la gestion des événements de soutien ... si vous pouvez utiliser l' signal module et la plaine de la vieille école UNIX/Linux signaux de --- tuant vos processus doucement, comme elle l'avait fait.

multiprocessing est pour l'exécution de fonctions au sein de votre existant (Python) code avec support pour plus de souplesse de communication au sein de la famille de processus. En particulier, il est préférable de construire votre multiprocessing de la CIB à travers le module de l' Queue objets, si possible, mais vous pouvez également utiliser Event objets et d'autres caractéristiques différentes (dont certaines sont, sans doute, construit autour d' mmap appui sur les plates-formes qui prennent en charge est suffisante).

Python multiprocessing module est destiné à fournir des interfaces et des fonctionnalités qui sont très similaires à threading tout en permettant Disponible à l'échelle de votre traitement entre plusieurs Processeurs/cœurs en dépit de la GIL. Il tire parti de toutes les fines SMP de verrouillage et la cohérence de l'effort qui a été fait par les développeurs de votre noyau de système d'exploitation.

threading est pour une fourchette relativement étroite de demandes d'e/S lié (n'avez pas besoin d'échelle sur plusieurs cœurs de PROCESSEUR) et qui bénéficient de la très faible latence de commutation et les frais généraux de fil de commutation (avec socle commun de mémoire) vs processus/changement de contexte. Sur Linux c'est presque l'ensemble vide (Linux processus de temps de commutation sont extrêmement proche de son fil-interrupteurs).

threading souffre de deux inconvénients majeurs en Python. L'un, bien sûr, est la mise en œuvre spécifique --- affectant principalement Disponible. C'est le GIL (Global Interprète de Verrouillage). Pour la plupart, la plupart Disponible programmes ne bénéficient pas de la disponibilité de plus de deux Processeurs (noyaux) et, souvent, les performances vont souffrir de la GIL conflits de verrouillage. Le plus grand problème qui n'est pas mise en œuvre spécifique, est que les threads partagent le même espace mémoire, les gestionnaires de signaux, les descripteurs de fichier et de certains autres systèmes d'exploitation des ressources. Ainsi, le programmeur doit être extrêmement prudent au sujet de l'objet de verrouillage, la gestion des exceptions et d'autres aspects de leur code qui sont à la fois subtils et qui peut tuer, de décrochage, ou de blocage de l'ensemble du processus (suite de threads).

Par contre, l' multiprocessing modèle donne à chaque processus de sa propre mémoire, les descripteurs de fichier, etc. D'un crash ou d'une exception non gérée dans l'un d'entre eux ne tuent que des ressources et robuste de la manipulation de la disparition d'un enfant, frère ou sœur processus peut être beaucoup plus facile que de débogage, d'isoler et de fixation ou de travailler autour des questions similaires dans les threads.

  • (Note: l'utilisation d' threading avec de grandes Python systèmes, tels que Numpy, peuvent souffrir de considérablement moins de GIL contention de la plupart de votre propre code Python serait. C'est parce qu'ils ont été spécialement conçues pour le faire).

Il est également intéressant de noter que Tordu offre encore une autre alternative qui est à la fois élégante et très difficile à comprendre. En gros, au risque de trop simplifier, au point où les fans de Torsadée peut tempête de ma maison avec des fourches et des torches, Tordu offre événementielle et coopérative multi-tâches à l'intérieur de tout (unique).

Pour comprendre comment cela est possible, on devrait lire sur les caractéristiques de l' select() (ce qui peut être construit autour de la select() ou poll() ou similaire OS appels système). Fondamentalement, c'est tous animés par la capacité à effectuer une demande de l'OS de sommeil dans l'attente d'une activité sur une liste de descripteurs de fichiers ou de dépassement du temps. L'éveil de chacun de ces appels à l' select() est un événement soit un impliquant d'entrée disponibles (lisible) sur un certain nombre de sockets ou des descripteurs de fichiers, ou de mise en mémoire tampon de l'espace devient disponible sur certains autres descripteurs ou des prises (en écriture), ou de certaines conditions exceptionnelles (TCP out-of-band POUSSER avais des paquets, par exemple), ou un DÉLAI d'attente.

Ainsi, le Tordu modèle de programmation est construite autour de la gestion de ces événements alors en boucle sur la "main" de gestionnaire, lui permettant d'envoyer les événements de vos gestionnaires.

Personnellement, je pense que de le nom, Tordu comme évocatrice du modèle de programmation ... depuis votre approche du problème doit être, dans un certain sens, "tordu" à l'intérieur. Plutôt que de concevoir votre programme comme une série d'opérations sur les données d'entrée et de sorties ou de résultats, vous écrivez votre programme en tant que service ou démon et de définir comment il réagit à divers événements. (En fait, le noyau principal de la boucle" Tordue d'un programme (généralement? toujours?) un reactor().

Les principaux défis liés à l'utilisation Tordu impliquer la torsion de votre esprit autour de l'événement piloté par le modèle et aussi renonçant à l'utilisation de bibliothèques de classes ou de trousses à outils qui ne sont pas écrites à co-opérer à l'intérieur de la torsion du cadre. C'est pourquoi Tordu fournit ses propres modules pour la gestion du protocole SSH, pour les malédictions, et de son propre sous-processus/popen fonctions, et de nombreux autres modules et les gestionnaires de protocole qui, à première vue, semble dupliquer les choses dans les bibliothèques standard Python.

Je pense qu'il est utile de comprendre Tordu sur un plan conceptuel, même si vous n'avez jamais l'intention de l'utiliser. Il peut donner un aperçu de la performance, la contention et la gestion des événements dans votre threading, le multitraitement et même des sous-processus de manutention ainsi que tout traitement distribué, vous vous engagez.

Encore un autre domaine de traitement, vous n'avez pas demandé à ce sujet, mais qui est à considérer, c'est que des distribué de traitement. Il existe de nombreux outils Python et de cadres pour la distribution de traitement et de calcul parallèle. Personnellement, je pense que le plus facile à utiliser est celui qui est le moins souvent considéré comme étant dans l'espace.

Il est presque banal de construire de traitement distribué autour de Redis. L'ensemble de magasin de clés peuvent être utilisés pour stocker les unités de travail et les résultats, Redis Listes peuvent être utilisées comme Queue() comme objet, et de la PUB/SUB support peut être utilisé pour Event-comme de la manipulation. Vous pouvez hachage vos clés et valeurs d'usage, répliqué sur une lâche la grappe de Redis cas, pour stocker de la topologie et de hachage-jeton de mappages d'assurer l'uniformité des fonctions de hachage et de basculement pour une mise à l'échelle au-delà de la capacité d'une seule instance de coordination de vos travailleurs et de regroupement de données (marinés, JSON, BFILS, ou YAML) d'entre eux.

Bien sûr, comme vous commencez à construire une échelle plus grande et la plus sophistiquée de la solution autour Redis, vous re-mettre en œuvre plusieurs fonctionnalités qui ont déjà été résolus par l'utilisation d'Hadoop, Zookeeper, Cassandra et ainsi de suite. Ceux-ci sont des modules de Python d'accès à leurs services.

Là, vous avez toute la gamme de possibilités de traitement de Python, de mono-thread, avec de simples appels synchrones pour les sous-processus, les piscines de sondés sous-processus, threads et de multitraitement, événementiel d'coopérative multi-tâches, et pour le traitement distribué.

67voto

EOL Points 24342

multiprocessing est un excellent couteau Suisse type de module. Il est plus général que les threads, vous pouvez même effectuer des calculs de distance. C'est donc le module, je vous suggère de l'utiliser.

L' subprocess module vous permet de lancer plusieurs processus, mais je trouve qu'il est moins pratique à utiliser que le nouveau module multiprocessing.

Les Threads sont très subtiles, et, avec Disponible, vous sont souvent limitées à un seul core, avec eux (même si, comme indiqué dans un des commentaires, le Mondial de l'Interprète de Verrouillage (GIL) peut être libéré dans le code C, appelé à partir de code Python).

Je crois que la plupart des fonctions des trois modules que vous citez peuvent être utilisés dans une plate-forme indépendante. Sur la portabilité côté, remarque que multiprocessing seulement est livré en standard depuis la version 2.6 de Python (une version pour certaines anciennes versions de Python n'existe pas, tout de même). Mais c'est un super module!

5voto

kriss Points 10450

Dans un cas similaire, j'ai opté pour des processus distincts et le peu de communication nécessaires creux d'une prise réseau. Il est très portable et très simple à faire à l'aide de python, mais probablement pas le plus simple (dans mon cas, j'ai eu aussi une autre contrainte: la communication avec d'autres processus écrit en C++).

Dans votre cas, je serais probablement aller pour les serveurs multi-processus, threads python, au moins lors de l'utilisation de Disponible, ne sont pas de vrais fils. Eh bien, ils sont système natif des threads mais C modules appelés à partir de Python peut ou ne peut pas libérer le GIL et permettre à d'autres threads pour exécuter lors de l'appel de blocage de code.

5voto

Jochen Ritzel Points 42916

Pour utiliser plusieurs processeurs dans CPython, votre seul choix est le module multiprocessing . CPython conserve un verrou sur ses éléments internes ( GIL ), ce qui empêche les threads des autres processeurs de fonctionner en parallèle. Le module multiprocessing crée de nouveaux processus (comme subprocess ) et gère la communication entre eux.

1voto

chiggsy Points 3695

Shell out et laissez-les unix pour faire vos travaux:

utilisation iterpipes pour envelopper les sous-processus et ensuite:

Ted Ziuba du site

INPUTS_FROM_YOU | xargs -n1 -0 -P NUM ./processus #NUM processus parallèles

OU

Gnu Parallèle servira également

Vous traîner avec GIL pendant que vous envoyer les coulisses des garçons pour faire de votre multicœur travail.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X