Question

Ces deux bibliothèques partagent une philosophie similaire et, par conséquent, des décisions de conception similaires.Mais ce benchmark WSGI populaire dit eventlet est bien plus lent que gevent.Qu’est-ce qui rend leur performance si différente ?

Comme je le sais, les principales différences entre eux sont :

  • gevent dépend intentionnellement de et est couplé à libev (libevent, précédemment) tandis que eventlet définit une interface de réacteur indépendante et implémente des adaptateurs particuliers en utilisant select, epoll, et le réacteur Twisted derrière. Une interface de réacteur supplémentaire entraîne-t-elle des performances critiques ?

  • gevent est principalement écrit en Cython tandis que eventlet est écrit en Python pur. Cython compilé nativement est-il si plus rapide que Python pur, pour des programmes peu informatiques mais liés aux IO ?

  • Primitives de gevent émuler les interfaces des bibliothèques standard tout en eventletLes primitives de diffèrent de la norme et fournissent une couche supplémentaire pour l'émuler. Une couche d'émulation supplémentaire rend-elle eventlet Ralentissez?

  • La mise en œuvre de eventlet.wsgi juste pire que gevent.pywsgi?

Je me le demande vraiment, car dans l’ensemble, ils me ressemblent beaucoup.

Était-ce utile?

La solution

Eh bien, gevent n'est pas "principalement" écrit en Cython, bien que certaines sections critiques le soient.

Cython fait une énorme différence.Les optimisations du processeur fonctionnent bien mieux avec le code compilé.La prédiction de branchement, par exemple, s'effondre dans les systèmes basés sur VM car l'indirection du branchement au niveau d'exécution d'une VM lui est opaque.L'empreinte du cache est plus étroite.Le code compilé fait ici une énorme différence, et les E/S peuvent être très sensibles à la latence.

Dans le même ordre d’idées, Libev est très rapide.Mêmes raisons.

Il ne semble pas que eventlet aurait dû utiliser le hub de sélection (Python 2.6 utilise généralement par défaut epoll).S'il était bloqué lors de la sélection, cela le rendrait vraiment lent (car Python doit convertir le select fd_set en une liste Python, donc ça devient moche quand il est au milieu d'une boucle).

Je n'ai fait aucun profilage, mais je serais prêt à parier que libev / libevent plus Cython font la grande différence.Notamment, certaines des primitives de thread sont en Cython en gevent.C'est un gros problème car beaucoup de code les touche indirectement via les E/S et même la bibliothèque standard à certains endroits.

Quant à la couche d'émulation supplémentaire de l'eventlet, elle semble y avoir beaucoup plus de rebond.En fait, le chemin du code semble construire des rappels et laisser le hub les appeler.eventlet semble faire davantage de comptabilité que le hub effectue dans gevent.Mais encore une fois, je n'en ai pas fait le profil.Quant au Monkeypatching lui-même, ils se ressemblent assez.

Le serveur WSGI est un autre serveur difficile.Notamment, l'analyse de l'en-tête dans gevent est reportée à la bibliothèque standard, alors qu'ils l'implémentent eux-mêmes dans eventlet.Je ne sais pas s’il s’agit d’un impact important ou non, mais il ne serait pas surprenant qu’il y ait quelque chose qui se cache là-dedans.Le plus révélateur est que le serveur d'eventlet est basé sur une version patchée par singe de la bibliothèque standard BaseHTTPServer.Je ne peux pas imaginer que ce soit tout à fait optimal.Gevent implémente un serveur conscient de l'émulation.

Autres conseils

Désolé pour la réponse tardive.

Il y a deux raisons principales à une grande différence de performances dans ce repère:

  • comme indiqué précédemment, les chemins critiques de gevent sont fortement optimisés
  • ce benchmark effectue des tests de résistance.Il n'est plus lié aux E/S, car il essaie de faire en sorte que la machine exécute autant de requêtes que possible.Et c'est là que le code Cythonisé brille.

"Dans le monde réel", cela ne se produit que lors des rafales de trafic "slashdot".Ce qui est important et il faut être prêt, mais lorsque cela se produit, vous réagissez en ajoutant plus de serveurs ou en désactivant les fonctionnalités gourmandes en ressources.Je n'ai pas vu de référence qui ajoute réellement plus de serveurs lorsque la charge augmente.

Si, en revanche, le benchmark simulait une charge « journée normale » (qui varierait d'un site Web à l'autre) mais pourrait généralement être approché par une demande, une pause aléatoire, une répétition.Moins nous faisons de pause, plus nous simulons de trafic.De plus, le côté client du benchmark devrait simuler la latence.Sous Linux, cela pourrait être fait en utilisant le génial netem[1], sinon, en mettant de petits délais avant les appels de réception/envoi (ce qui serait très difficile car les tests utilisent généralement des bibliothèques de niveau supérieur).

Maintenant, si ces conditions sont remplies, nous évaluerions réellement les problèmes liés aux IO.Mais les résultats ne seraient pas trop impressionnants :tous les candidats ont servi avec succès des chargements de 10, 50 et même 200 qps.Ennuyeux, non ?Nous pourrions ainsi mesurer la distribution de la latence, le temps nécessaire pour répondre à 99 % des requêtes, etc.Gevent montrerait encore de meilleurs résultats.Mais la différence ne serait guère impressionnante.

[1] Simuler des paquets retardés et abandonnés sous Linux

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