Une alternative propre et légère à la torsion de Python? [fermé]

222

Il y a très longtemps, j'ai écrit une web-spider que j'ai multithreadée pour permettre aux requêtes simultanées de se produire en même temps. C'était dans ma jeunesse Python, dans les jours avant que je connaissais le GIL et les malheurs associés qu'il crée pour le code multithread (IE, la plupart du temps, les choses finissent par être sérialisées!) ...

Je voudrais retravailler ce code pour le rendre plus robuste et mieux performer. Il y a essentiellement deux façons de le faire: je pourrais utiliser le nouveau module de multitraitement dans 2.6+ ou je pourrais opter pour un modèle basé sur un réacteur / événement d'une certaine sorte. Je préfère faire plus tard, car il est beaucoup plus simple et moins sujet aux erreurs.

La question porte donc sur le cadre le mieux adapté à mes besoins. Voici une liste des options que je connais jusqu'à présent:

  • Twisted : Le grand-père des frameworks de réacteurs Python: semble complexe et un peu gonflé cependant. Courbe d'apprentissage abrupte pour une petite tâche.
  • Eventlet : Des gars du lindenlab . Cadre basé sur Greenlet et orienté vers ce type de tâches. J'ai cependant regardé le code et ce n'est pas trop joli: non compatible pep8, parsemé d'impressions (pourquoi les gens font ça dans un framework!?), L'API semble un peu incohérente.
  • PyEv : Immature, il ne semble pas que quiconque l'utilise actuellement, bien qu'il soit basé sur libevent, il a donc un solide backend.
  • asyncore : Du stdlib: über bas niveau, il semble que beaucoup de travail de base soit nécessaire pour faire décoller quelque chose.
  • tornade : Bien qu'il s'agisse d'un produit orienté serveur conçu pour desservir des sites Web dynamiques, il dispose d'un client HTTP asynchrone et d'un simple ioloop . On dirait que cela pourrait faire le travail, mais pas ce à quoi il était destiné. [edit: ne fonctionne pas sur Windows malheureusement, ce qui compte pour moi - c'est une exigence pour moi de prendre en charge cette plate-forme boiteuse]

Y a-t-il quelque chose que j'ai manqué du tout? Il doit sûrement y avoir une bibliothèque qui correspond au bonbon d'une bibliothèque de réseau asynchrone simplifiée!

[edit: merci à intgr pour son pointeur sur cette page . Si vous faites défiler vers le bas, vous verrez qu'il y a une très belle liste de projets qui visent à aborder cette tâche d'une manière ou d'une autre. Il semble en fait que les choses aient effectivement évolué depuis la création de Twisted: les gens semblent désormais privilégier une solution basée sur la co-routine plutôt qu'une solution traditionnelle orientée réacteur / callback. Les avantages de cette approche sont un code plus clair et plus direct: j'ai certainement trouvé dans le passé, surtout lorsque vous travaillez avec boost.asioen C ++, ce code basé sur le rappel peut conduire à des conceptions difficiles à suivre et relativement obscures à l'œil non averti. L'utilisation de co-routines vous permet d'écrire du code qui semble au moins un peu plus synchrone. Je suppose que maintenant ma tâche est de déterminer laquelle de ces nombreuses bibliothèques j'aime le look et d'essayer! Heureux d'avoir demandé maintenant ...]

[modifier: peut-être d'intérêt pour quiconque a suivi ou est tombé sur cette question ou se soucie de ce sujet dans tous les sens: j'ai trouvé un très bon résumé de l'état actuel des outils disponibles pour ce travail]

jkp
la source
14
Python est multithread, il ne permet tout simplement pas à deux threads d'exécuter du code Python simultanément.
intgr
86
J'ai appris beaucoup plus de votre question que des réponses.
Denis Otkidach
2
@Denis: heh, merci je suppose! Il y a eu aussi de bons pointeurs dans les réponses, en particulier les intégrateurs. Je connaissais de nombreuses options et je ne voulais pas seulement que les réponses en contiennent, alors j'ai pensé que j'allais me donner la peine de préciser ce que je savais :)
jkp
5
> les gens semblent maintenant préférer une solution basée sur la co-routine plutôt qu'une solution traditionnelle orientée réacteur / rappel. Ce n'est pas une comparaison sensée. les «solutions basées sur la co-routine» et les solutions «orientées réacteur» sont orthogonales. (Ignorant le fait que Python n'a pas de coroutines) Jetez un coup d'œil aux rappels inline de Twisted pour voir comment vous pouvez avoir le style de programmation que vous semblez préférer avec une couche réseau robuste et mature qui ne vous exposera pas à des idiosyncrasies de plateforme complexes.
Jean-Paul Calderone,
2
Quelques points à ajouter: 1. Tornado fonctionne très bien sur Windows. Il n'est tout simplement pas aussi performant et évolutif car il l'utilise selectpour le multiplexage d'E / S. Mais vous devriez pouvoir en tirer une performance décente avec tornado-pyuv . 2. Il y a maintenant asyncio dans Python 3.3+ et son trollius backport qui permet d'exécuter n'importe quelle application Tornado dans sa boucle d'événement (Twisted sera bientôt supporté).
schlamar

Réponses:

28

J'ai aimé le module Python de concurrence qui s'appuie sur des microthreads Stackless Python ou des Greenlets pour un filetage léger. Toutes les E / S de réseau bloquantes sont rendues asynchrones de manière transparente via une seule libeventboucle, donc elles devraient être presque aussi efficaces qu'un vrai serveur asynchrone.

Je suppose que c'est similaire à Eventlet de cette façon.

L'inconvénient est que son API est assez différente de sockets/ threadingmodules de Python ; vous devez réécrire une bonne partie de votre application (ou écrire une couche de shim de compatibilité)

Edit: Il semble qu'il y ait aussi cogen , qui est similaire, mais utilise des générateurs améliorés de Python 2.5 pour ses coroutines, au lieu de Greenlets. Cela le rend plus portable que la concurrence et d'autres alternatives. Les E / S réseau se font directement avec epoll / kqueue / iocp.

intgr
la source
@intgr: d'excellents liens. J'avais déjà vu ces deux-là auparavant, ce sont des choses que j'espérais voir disparaître. +1
jkp
3
On dirait que la concurrence est un projet mort avec leur dernière mise à jour il y a quatre ans.
Gewthen
projet est mort, Hyves aussi!
Bahadir Cambel
1
Beaucoup de choses se sont passées depuis Python 2.5. asyncio en Python 3.5 est génial.
Joseph Sheedy
99

Twisted est complexe, vous avez raison. Twisted n'est pas gonflé.

Si vous jetez un œil ici: http://twistedmatrix.com/trac/browser/trunk/twisted vous trouverez une suite organisée, complète et très bien testée de nombreux protocoles d'Internet, ainsi qu'un code d'aide à écrire et déployer des applications réseau très sophistiquées. Je ne confondrais pas ballonnement avec exhaustivité.

Il est bien connu que la documentation Twisted n'est pas la plus conviviale à première vue, et je pense que cela repousse un nombre malheureux de personnes. Mais Twisted est incroyable (à mon humble avis) si vous mettez le temps. Je l'ai fait et cela en a valu la peine, et je recommanderais à d'autres d'essayer de même.

clemesha
la source
4
@clemesha: peut-être que vous avez raison, et ce n'est pas surchargé, mais on a l'impression qu'il y en a un peu trop pour me permettre de faire quelque chose de simple. Je comprends la programmation asynchrone, j'ai travaillé en C ++ avec boost :: asio donc les concepts ne sont pas nouveaux, mais c'est tout le gumph qui correspond à faire des trucs tordus: c'est un tout nouveau monde, un peu comme django pour les trucs web. Encore une fois, lorsque je fais des trucs Web, je travaille avec du code WSGI léger et je ne branche que ce dont j'ai besoin. Des chevaux pour les cours, je suppose.
jkp
7
@clemesha: euh, j'ai franchi le pas aujourd'hui pour jeter un coup d'œil: la torsion pèse 20 Mo! Même le noyau est de 12 Mo ... si ce n'est pas gonflé, je ne sais pas trop ce que c'est.
jkp
29
Les API Twisted de base sont assez petites (réacteur, différé, protocole). La plupart du code Twisted est une implémentation de protocole asynchrone utilisant ces bases. "Ballonnement" n'est pas un adjectif utile ici (ou même dans la plupart des cas). La taille de Twisted est raisonnable pour la quantité de choses qu'elle fait.
daf
56

gevent est eventlet nettoyé .

Du point de vue de l'API, il suit les mêmes conventions que la bibliothèque standard (en particulier, les modules de thread et de multitraitement) où cela a du sens. Vous avez donc des choses familières comme Queue et Event avec lesquelles travailler.

Il prend uniquement en charge libevent ( mise à jour: libev depuis 1.0 ) en tant qu'implémentation du réacteur, mais en profite pleinement, avec un serveur WSGI rapide basé sur libevent-http et la résolution des requêtes DNS via libevent-dns, par opposition à l'utilisation d'un pool de threads comme la plupart des autres bibliothèques faire. ( mise à jour: puisque 1.0 c-ares est utilisé pour effectuer des requêtes DNS asynchrones; threadpool est également une option.)

Comme eventlet, il rend les rappels et les différés inutiles en utilisant des greenlets .

Consultez les exemples: téléchargement simultané de plusieurs URL , discussion en ligne longue .

Denis Bilenko
la source
4
Je vais second gevent - Après avoir passé en revue de nombreuses solutions, gevent a très bien fonctionné pour moi. Cela m'a permis de conserver la meilleure partie de mon programme existant, et les changements qui ont été nécessaires étaient insignifiants - Mieux encore, si le code doit être maintenu dans 3, 4, 5, ... ans, il fait encore sens pour quiconque ne connaît pas gevent, le plus grand showstopper pour Twisted est la forte courbe d'apprentissage, cela pose des problèmes non seulement lors de la mise en œuvre, mais aussi plus loin sur la ligne pendant la maintenance ...
Martin Tournoij
27

Une comparaison très intéressante de tels frameworks a été compilée par Nicholas Piël sur son blog: ça vaut le coup d'être lu!

jkp
la source
2
Bien que je convienne que cet article était une lecture intéressante, je pense qu'il vaut la peine de considérer la validité des repères présentés. Voir les commentaires ici: reddit.com/r/programming/comments/ahepg/…
clemesha
1
@clemesha, bien que le point de cette page reddit mérite d'être noté, le test de performance a été effectué sur une machine à double cœur et ne souffrait probablement pas d'une faille fatale décrite. Je suppose qu'il est possible que le client et le serveur fonctionnent sur le même noyau, mais cela ne semble pas probable.
Peter Hansen
15

Aucune de ces solutions n'évitera le fait que le GIL empêche le parallélisme CPU - ce sont juste de meilleurs moyens d'obtenir le parallélisme IO que vous avez déjà avec les threads. Si vous pensez que vous pouvez faire mieux IO, poursuivez certainement l'un d'entre eux, mais si votre goulot d'étranglement est dans le traitement des résultats, rien ici ne vous aidera, sauf pour le module de multitraitement.

Adam Hupp
la source
Quel est le problème avec l'utilisation de plusieurs processus?
Emil Ivanov
3
Rien du tout, d'où la suggestion d'utiliser le module multitraitement.
Adam Hupp
11

Je n'irais pas jusqu'à appeler Twisted ballonné, mais il est difficile de se couvrir la tête. J'ai évité de m'installer vraiment dans un apprentissage pendant un bon moment car j'ai toujours voulu quelque chose d'un peu plus facile pour les «petites tâches».

Cependant, maintenant que j'ai travaillé avec, je dois dire que le fait d'avoir toutes les piles incluses est TRÈS agréable.

Toutes les autres bibliothèques asynchrones avec lesquelles j'ai travaillé finissent par être beaucoup moins matures qu'elles ne le semblent même. La boucle d'événement de Twisted est solide.

Je ne sais pas trop comment résoudre la courbe d'apprentissage Twisted raide. Il pourrait être utile que quelqu'un le fourche et nettoie quelques éléments, comme la suppression de toutes les erreurs de compatibilité descendante et les projets morts. Mais c'est la nature d'un logiciel mature, je suppose.

rhettg
la source
Si vous avez déjà regardé comment le réacteur gtk est implémenté sous Windows (sondage hardcore toutes les 10 ms: twistedmatrix.com/trac/browser/trunk/twisted/internet/… ), vous n'appeleriez pas cela "mature" ...
schlamar
2
Salut @schlamar. Ce méchant hack a été implémenté comme solution de contournement pour quelques bugs assez sérieux dans GTK +, à l'époque où il y avait beaucoup moins de soucis concernant l'efficacité énergétique :). Mais, la beauté de Twisted est que nous pouvons avoir ce bogue une fois , le corriger dans le cadre, et nos utilisateurs n'ont pas à s'en soucier. Souhaitez-vous contribuer un correctif qui résout ce problème et se débarrasse de (obsolète puis supprimé plus tard) PortableGtkReactor?
Glyph
1
@Glyph J'ai ajouté des conseils utiles sur twistedmatrix.com/trac/ticket/4744#comment:2 si quelqu'un d'autre veut s'attaquer à ce problème, car certains de ces problèmes existent toujours. BTW, vous auriez pu résoudre ce problème beaucoup plus efficacement en planifiant des rappels entre les deux boucles d'événements.
schlamar
7

Kamaelia n'a pas encore été mentionnée. Son modèle de concurrence est basé sur le câblage des composants avec le passage de messages entre les boîtes de réception et les boîtes d'envoi. Voici un bref aperçu.

Steven Kryskalla
la source
5
J'ai utilisé kamaelia pour une application - c'était extrêmement douloureux. À mon humble avis, il existe d'autres meilleures options pour concurrenct en python (dont la plupart sont mentionnés ci-dessus)
Ben Ford
7

J'ai commencé à utiliser le twisted pour certaines choses. La beauté de celui-ci est presque parce qu'il est "gonflé". Il existe des connecteurs pour à peu près tous les protocoles principaux disponibles. Vous pouvez avoir un robot jabber qui prendra les commandes et les publiera sur un serveur irc, les enverra par courrier électronique à quelqu'un, exécutera une commande, lira à partir d'un serveur NNTP et surveillera les modifications d'une page Web. La mauvaise nouvelle, c'est qu'il peut faire tout cela et rendre les choses trop complexes pour des tâches simples comme l'OP expliqué. L'avantage de python est que vous n'incluez que ce dont vous avez besoin. Ainsi, bien que le téléchargement puisse être de 20 Mo, vous ne pouvez inclure que 2 Mo de bibliothèques (ce qui est encore beaucoup). Ma plus grande plainte avec Twisted est bien qu'ils incluent des exemples, vous êtes tout seul au-delà d'un serveur TCP de base.

Bien que ce ne soit pas une solution python, j'ai vu node.js gagner beaucoup plus de traction ces derniers temps. En fait, j'ai envisagé d'envisager des projets plus petits, mais je grince des dents quand j'entends javascript :)

vrillusions
la source
Je suis un grand fan de Python. - Découvrez «Javascript - The good parts» de Douglas Crockford (3, 4 vidéos). Et jetez un œil à CoffeeScript. Il s'avère que JS a des choses que Python devrait avoir, à l'exception de la syntaxe, haha. CS a essayé d'atténuer cela, mais est un peu maladroit à ce sujet ...
Robert Siemer
4

Il existe un bon livre sur le sujet: "Twisted Network Programming Essentials", par Abe Fettig. Les exemples montrent comment écrire du code très Pythonic, et pour moi personnellement, ne me semble pas basé sur un framework gonflé. Regardez les solutions dans le livre, si elles ne sont pas propres, alors je ne sais pas ce que signifie propre.

Ma seule énigme est la même que celle que j'ai avec d'autres frameworks, comme Ruby. Je m'inquiète, est-ce que cela augmente Je détesterais engager un client dans un framework qui va avoir des problèmes d'évolutivité.

mrsmoothie
la source
4

Whizzer est un petit framework de socket asynchrone qui utilise pyev. C'est très rapide, principalement à cause de pyev. Il essaie de fournir une interface similaire comme tordue avec quelques légères modifications.

bfrog
la source
2

Essayez également Syncless . Il est basé sur coroutine (il est donc similaire à Concurrence, Eventlet et gevent). Il implémente des remplacements non bloquants pour socket.socket, socket.gethostbyname (etc.), ssl.SSLSocket, time.sleep et select.select. C'est rapide. Il a besoin de Stackless Python et libevent. Il contient une extension Python obligatoire écrite en C (Pyrex / Cython).

pts
la source
2

Je confirme la bonté de syncless . Il peut utiliser libev (la version la plus récente, la plus propre et la plus performante de libevent). Il y a quelques temps, il n'a pas autant de support que libevent, mais maintenant le processus de développement va plus loin et est très utile.

Robert Zaremba
la source
1

Si vous voulez juste une bibliothèque de requêtes HTTP simplifiée et légère, je trouve Unirest vraiment bon

ejectamenta
la source
0

Vous êtes invités à jeter un œil à PyWorks, qui adopte une approche très différente. Il permet aux instances d'objet de s'exécuter dans leur propre thread et effectue des appels de fonction à cet objet asynchrone.

Laissez simplement une classe hériter de Task au lieu d'objet et c'est async, tous les appels de méthodes sont des proxys. Les valeurs de retour (si vous en avez besoin) sont des proxys futurs.

res = obj.method( args )
# code continues here without waiting for method to finish
do_something_else( )
print "Result = %d" % res # Code will block here, if res not calculated yet

PyWorks peut être trouvé sur http://bitbucket.org/raindog/pyworks

renejsum
la source
1
Bien que cela soit intéressant et puisse convenir à certaines tâches, l'utilisation de threads pour la mise en réseau est mauvaise (en particulier sur Python en raison de GIL). Et c'était exactement la question: un framework événementiel ou avec multiprocessing. Donc, votre réponse est clairement hors de portée ...
schlamar