Question

Quels sont les modules utilisés pour écrire des applications multi-thread en Python? Je suis au courant des mécanismes de concurrence de base fournis par la langue et aussi Stackless Python , mais quels sont leurs respectifs forces et faiblesses?

Était-ce utile?

La solution

Afin de complexité croissante:

Utilisez la filetage Module

Avantages:

  • Il est vraiment facile d'exécuter une fonction (tout appelable en fait) dans sa propre fil.
  • Le partage de données est sinon facile (serrures ne sont jamais faciles :), à moins simple.

Moins:

Utilisez la multitraitement le module

Dans le cas simple d'utilisation ce ressemble exactement à l'aide threading sauf que chaque tâche est exécutée dans son propre processus pas son propre fil. (Presque littéralement: Si vous prenez par exemple Eli et remplacer threading avec multiprocessing, Thread, avec Process et Queue (module) avec multiprocessing.Queue, il devrait fonctionner très bien.)

Avantages:

  • réel pour toutes concurrency tâches (pas d'interprète de verrouillage global).
  • Balances à plusieurs processeurs, peut même échelle à plusieurs machines .

Moins:

  • Processus sont plus lents que les threads.
  • Le partage des données entre les processus est plus compliqué que de fils.
  • La mémoire est pas implicitement partagé. Vous devez soit partager explicitement ou vous devez décaper les variables et les renvoyer en arrière. Cela est plus sûr, mais plus difficile. (S'il importe de plus en plus les développeurs Python semblent pousser les gens dans ce sens.)

A l'aide d'un modèle d'événement, tel que Twisted

Avantages:

  • Vous obtenez un contrôle extrêmement précis sur la priorité, sur ce qui exécute quand.

Moins:

  • Même avec une bonne bibliothèque, la programmation asynchrone est généralement plus difficile que la programmation par thread, difficile tant en termes de compréhension de ce qui est censé se produire et en termes de débogage ce qui se passe réellement.

tous les cas, je suppose que vous comprenez déjà beaucoup des questions liées aux multi-tâches, en particulier la question délicate de la façon de partager des données entre les tâches. Si pour une raison quelconque, vous ne savez pas quand et comment utiliser les verrous et les conditions que vous devez commencer par ceux-ci. Code Multitâche est plein de subtilités et gotchas, et il est vraiment préférable d'avoir une bonne compréhension des concepts avant de commencer.

Autres conseils

Vous avez déjà obtenu une juste variété de réponses, de « fils faux » jusqu'aux cadres externes, mais je l'ai vu Queue.Queue mention de personne -. La « sauce secrète » de filetage CPython

Pour développer: aussi longtemps que vous n'avez pas besoin de chevauchement CPU lourd traitement pur-Python (dans ce cas, vous avez besoin multiprocessing - mais il est livré avec sa propre implémentation de Queue aussi, vous pouvez donc avec quelques précautions nécessaires appliquer les conseils généraux que je donne ;-), intégré dans Python threading fera ... mais il le fera beaucoup mieux si vous l'utilisez à bon escient , par exemple, comme suit.

« oublier » la mémoire partagée, censé être le principal et de filetage vs multitraitement - ne, n'a jamais pas bien, il n'échelle pas bien, ne le sera jamais. Utilisez la mémoire partagée uniquement pour les structures de données qui sont mises en place une fois avant vous engendrez sous-fils et jamais changé par la suite - pour tout le reste, faire un à enfilez responsable de cette ressource et communiquer avec ce fil via Queue.

Consacrer un fil spécialisé à chaque ressource que vous penseriez normalement à protéger par des verrous: une structure de données mutable ou d'un groupe cohérent de celui-ci, une connexion à un processus externe (un DB, un serveur XMLRPC, etc.), un fichier externe, etc, etc Obtenez un petit pool de threads pour des tâches allant à usage général qui n'ont pas ou ont besoin d'une ressource dédiée de ce genre - ne pas threads spawn en fonction des besoins, ou thread- Les frais généraux de commutation vous submerger.

La communication entre les deux fils est toujours via Queue.Queue - une forme de passage de message, le seul fondement sain d'esprit pour multitraitement (en plus de mémoire transactionnelle, ce qui est prometteur, mais dont je ne connais pas les implémentations de production digne sauf en Haskell).

Chaque thread dédié la gestion d'une ressource unique (ou petit ensemble cohérent de ressources) à l'écoute des demandes sur une instance Queue.Queue spécifique. Discussions dans une piscine attente sur une seule Queue.Queue (file d'attente est solidement threadsafe et pas vous ne parvenez pas à ce sujet) partagé.

Les threads qui ont juste besoin de faire la queue une demande une file d'attente (dédié ou mutualisé) le font sans attendre les résultats, et de progresser. Les threads qui éventuellement ont besoin d'un résultat ou la confirmation d'une demande file d'attente d'une paire (demande, receivingqueue) avec une instance de Queue.Queue ils ont juste fait, et éventuellement, lorsque la réponse ou la confirmation est indispensable pour procéder, ils obtiennent (en attente ) de leur receivingqueue. Assurez-vous que vous êtes prêt à-réponses d'erreur ainsi que les réponses réelles ou des confirmations (les deferreds Twisted sont grands à l'organisation de ce genre de réponse structurée, BTW!).

Vous pouvez également utiliser la file d'attente aux instances « parc » des ressources qui peuvent être utilisées par un fil quelconque, mais jamais être partagées entre plusieurs threads à un moment donné (connexions DB avec quelques compoents de DBAPI, curseurs avec d'autres, etc.) - ce vous permet de vous détendre l'exigence dédié fils en faveur de la mise en commun plus (un thread pool qui obtient de la file d'attente partagée une demande ayant besoin d'une ressource queueable va obtenir cette ressource de la file d'attente apppropriate, attente si nécessaire, etc etc).

Twisted est en fait un bon moyen d'organiser cette menuet (ou la danse carrée comme le cas), non seulement grâce à deferreds mais à cause de son son, l'architecture de base solide, hautement évolutive: vous pouvez arranger les choses à utiliser des fils ou que lorsque les sous-processus vraiment justifié, tout en faisant la plupart des choses normalement considérées comme fil digne dans un seul thread par événement.

Mais, je me rends compte Twisted est pas pour tout le monde - les « dévouer des ressources piscine, utilisez la file d'attente le Wazoo, ne font jamais rien besoin d'un verrouillage ou, Guido interdit, toute procédure de synchronisation encore plus avancée, comme sémaphores ou condition "approche peut encore être utilisée même si vous ne pouvez pas envelopper votre tête autour des méthodes événementielles-async, et livrera encore plusla fiabilité et de performances que toute autre approche de filetage largement applicable que j'ai jamais trébuché sur.

Cela dépend de ce que vous essayez de faire, mais je suis partie juste en utilisant le module threading dans la bibliothèque standard, car il est vraiment facile de prendre une fonction et il suffit d'exécuter dans un thread séparé.

from threading import Thread

def f():
    ...

def g(arg1, arg2, arg3=None):
    ....

Thread(target=f).start()
Thread(target=g, args=[5, 6], kwargs={"arg3": 12}).start()

Et ainsi de suite. Je souvent une configuration producteur / consommateur en utilisant une file d'attente synchronisé fourni par le module de Queue

from Queue import Queue
from threading import Thread

q = Queue()
def consumer():
    while True:
        print sum(q.get())

def producer(data_source):
    for line in data_source:
        q.put( map(int, line.split()) )

Thread(target=producer, args=[SOME_INPUT_FILE_OR_SOMETHING]).start()
for i in range(10):
    Thread(target=consumer).start()

Kamaelia est un cadre de python pour la création d'applications avec beaucoup de processus de communication.

  

     

(source: kamaelia.org ) Kamaelia - Concurrency fait utile, amusant

     

Dans Kamaelia vous construire des systèmes de composants simples qui parlent les uns aux autres . Cela accélère le développement, la maintenance et aide massivement signifie également que vous construire des logiciels naturellement en même temps . Il est destiné à être accessible par tout développeur , y compris les novices. Il est aussi amusant :)

     

Quel type de systèmes? Les serveurs de réseau, les clients, les applications de bureau, des jeux basés pygame, les systèmes de transcoder et pipelines, les systèmes de télévision numérique, effaceurs de spam, des outils pédagogiques, et une bonne quantité plus :)

Voici une vidéo de PyCon 2009. Il commence en comparant Kamaelia Twisted et Python parallèle et donne alors une main sur la démonstration de Kamaelia.

facile avec accès simultané Kamaelia - Partie 1 (59:08)
facile avec accès simultané Kamaelia - Partie 2 (18:15)

En ce qui concerne Kamaelia, la réponse ci-dessus couvre pas vraiment l'avantage ici. L'approche de Kamaelia fournit une interface unifiée, qui est pragmatique pas parfait, pour faire face à des fils, des générateurs et des processus dans un système unique pour la concurrence.

Fondamentalement, il fournit une métaphore d'une chose en cours d'exécution qui a des boîtes de réception, et Outboxes. Vous envoyez des messages à Outboxes, et quand câblés ensemble, flux de messages de Outboxes boîtes de réception. Cette métaphore / API reste le même si vous utilisez des générateurs, des threads ou processus, ou de parler à d'autres systèmes.

La partie « pas parfait » est due au sucre syntaxique pas ajouté encore pour les boîtes de réception et Outboxes (bien que ce soit en cours de discussion) -. L'accent est mis sur la sécurité / facilité d'utilisation dans le système

En prenant l'exemple des producteurs et consommateurs utilisant le threading nu ci-dessus, cela devient ceci dans Kamaelia:

Pipeline(Producer(), Consumer() )

Dans cet exemple, il n'a pas d'importance si ceux-ci sont des éléments filetés ou non, la seule différence entre eux dans une perspective d'utilisation est la classe de base pour le composant. Générateur composants de communiquer en utilisant des listes, des composants filetés en utilisant Queue.Queues et procédé à base en utilisant os.pipes.

La raison derrière cette approche est que pour le rendre plus difficile à faire du mal à des bugs de débogage. Dans le filetage - ou tout de mémoire partagée concurrency que vous avez, le numéro un problème que vous faites face à des mises à jour est accidentellement cassé de données partagées. En utilisant un message vous en passant à éliminer un classe de bogues.

Si vous utilisez le filetage nu et serrures partout où vous travaillez généralement sur l'hypothèse que lorsque vous écrivez du code que vous ne faire aucune erreur. Alors que nous aspirons tous à cela, il est très rare qui va se passer. En enveloppant le comportement de verrouillage dans un endroit où vous simplifiez les choses peuvent mal tourner. (Gestionnaires de l'aide contextuelle, mais ne permettent pas de mises à jour accidentelles en dehors du gestionnaire de contexte)

Évidemment pas chaque morceau de code peut être écrit en passant un message et le style partagé qui est la raison pour laquelle Kamaelia dispose également d'un logiciel simple mémoire transactionnelle (STM), qui est une idée vraiment bien avec un nom méchant - il est plus comme le contrôle de version variables - à savoir vérifier certaines variables, les mettre à jour et valider en arrière. Si vous obtenez un choc vous rincer et répéter.

Liens utiles:

Quoi qu'il en soit, je souhaite que est une réponse utile. FWIW, la principale raison derrière la configuration de Kamaelia est de rendre plus sûr et plus facile concurrency à utiliser dans les systèmes de python, sans la queue qui remue le chien. (Le grand seau de composants

Je peux comprendre pourquoi l'autre réponse Kamaelia a été modded vers le bas, car même pour moi, il ressemble plus à une annonce qu'une réponse. Comme l'auteur de Kamaelia il est agréable de voir l'enthousiasme que j'espère que cela contient un peu un contenu plus pertinent: -)

Et voilà ma façon de dire, s'il vous plaît prendre la mise en garde que cette réponse est par définition biaisée, mais pour moi, le but de Kamaelia est d'essayer de conclure ce qui est de l'OMI les meilleures pratiques. Je vous suggère d'essayer quelques systèmes dehors, et de voir ce qui fonctionne pour vous. (Même si ce ne convient pas pour débordement de pile, désolé - je suis nouveau sur ce forum: -)

J'utiliser les microfiletages (tasklets) de Stackless Python, si je devais utiliser des fils du tout.

est construire un jeu entier en ligne (massivly multijoueur) autour Stackless et son principe de multithreading -. Car l'original est juste pour ralentir pour la propriété multijoueur massivly du jeu

Discussions dans CPython sont largement découragés. L'une des raisons est le GIL - un verrou interprète global - qui sérialise filetage pour de nombreuses parties de l'exécution. Mon experiance est, qu'il est vraiment difficile de créer des applications rapides de cette façon. Mon exemple codages où tout plus lent avec filetage -. Avec un noyau (mais beaucoup d'attente pour l'entrée aurait dû faire un peu de performance augmente possible)

Avec CPython, utilisez plutôt des processus séparés, si possible.

Si vous voulez vraiment vous salir les mains, vous pouvez essayer utilisant des générateurs à coroutines faux . Il est sans doute pas le plus efficace en termes de travail en cause, mais coroutines-vous offre un contrôle très fin de coopérative multitâches plutôt que le traitement multitâche préemptif, vous trouverez ailleurs.

Un avantage que vous trouverez est que dans l'ensemble, vous aurez pas besoin serrures ou mutex lors de l'utilisation multi-tâches coopératif, mais l'avantage plus important pour moi était la vitesse de commutation presque nulle entre « fils ». Bien sûr, Stackless Python est dit être très bon pour cela aussi; et puis il y a Erlang, si elle ne le fait pas Vous pour être Python.

Probablement le plus grand inconvénient de multi-tâches coopérative est le manque de solution de contournement pour bloquer E / S. Et dans les coroutines truquées, vous rencontrerez aussi la question que vous ne pouvez pas passer « fils » de quoi que ce soit, mais le niveau haut de la pile dans un fil.

Une fois que vous avez fait une même demande un peu complexe avec coroutines faux, vous allez vraiment commencer à apprécier le travail qui va dans la planification des processus au niveau du système d'exploitation.

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