Je suis nouveau dans les gevents et les greenlets. J'ai trouvé une bonne documentation sur la façon de travailler avec eux, mais aucun ne m'a donné de justification sur comment et quand je devrais utiliser des greenlets!
- Dans quoi sont-ils vraiment bons?
- Est-ce une bonne idée de les utiliser dans un serveur proxy ou non?
- Pourquoi pas des fils?
Ce dont je ne suis pas sûr, c'est de savoir comment ils peuvent nous fournir une concurrence d'accès s'ils sont essentiellement des co-routines.
threading.Thread
est en fait un thread OS avec toutes les ramifications. Ce n'est donc vraiment pas aussi simple. Au fait, Jython n'a pas de GIL AFAIK et PyPy essaie de s'en débarrasser aussi.Réponses:
Les greenlets fournissent la concurrence mais pas le parallélisme. La concurrence est le moment où le code peut s'exécuter indépendamment d'un autre code. Le parallélisme est l'exécution simultanée de code concurrent. Le parallélisme est particulièrement utile lorsqu'il y a beaucoup de travail à faire dans l'espace utilisateur, et c'est généralement un travail lourd en CPU. La simultanéité est utile pour séparer les problèmes, ce qui permet de planifier et de gérer plus facilement différentes parties en parallèle.
Les greenlets brillent vraiment dans la programmation réseau où les interactions avec un socket peuvent se produire indépendamment des interactions avec d'autres sockets. Ceci est un exemple classique de concurrence. Étant donné que chaque greenlet s'exécute dans son propre contexte, vous pouvez continuer à utiliser des API synchrones sans thread. C'est une bonne chose car les threads sont très chers en termes de mémoire virtuelle et de surcharge du noyau, de sorte que la concurrence que vous pouvez obtenir avec les threads est nettement inférieure. De plus, le threading en Python est plus cher et plus limité que d'habitude en raison du GIL. Les alternatives à la concurrence sont généralement des projets comme Twisted, libevent, libuv, node.js, etc., où tout votre code partage le même contexte d'exécution et enregistre les gestionnaires d'événements.
C'est une excellente idée d'utiliser des greenlets (avec un support réseau approprié tel que via gevent) pour écrire un proxy, car votre gestion des requêtes peut s'exécuter indépendamment et doit être écrite comme telle.
Les greenlets fournissent la concurrence pour les raisons que j'ai données plus tôt. La concurrence n'est pas le parallélisme. En masquant l'enregistrement des événements et en effectuant la planification pour vous sur les appels qui bloqueraient normalement le thread actuel, des projets comme gevent exposent cette concurrence sans nécessiter de modification d'une API asynchrone, et à un coût nettement inférieur pour votre système.
la source
import hashlib def checksum_md5(filename): md5 = hashlib.md5() with open(filename,'rb') as f: for chunk in iter(lambda: f.read(8192), b''): md5.update(chunk) return md5.digest()
En prenant la réponse de @ Max et en y ajoutant une certaine pertinence pour la mise à l'échelle, vous pouvez voir la différence. J'ai réalisé cela en modifiant les URL à remplir comme suit:
J'ai dû abandonner la version multiprocessus car elle tombait avant d'en avoir 500; mais à 10 000 itérations:
Vous pouvez donc voir qu'il y a une différence significative dans les E / S en utilisant gevent
la source
En corrigeant la réponse de @TemporalBeing ci-dessus, les greenlets ne sont pas "plus rapides" que les threads et c'est une technique de programmation incorrecte de générer 60000 threads pour résoudre un problème de concurrence, un petit pool de threads est plutôt approprié. Voici une comparaison plus raisonnable (de mon post reddit en réponse aux personnes citant ce post SO).
Voici quelques résultats:
le malentendu que tout le monde a à propos des E / S non bloquantes avec Python est la croyance que l'interpréteur Python peut s'occuper du travail de récupération des résultats à partir des sockets à grande échelle plus rapidement que les connexions réseau elles-mêmes ne peuvent renvoyer des E / S. Bien que cela soit certainement vrai dans certains cas, ce n'est pas aussi souvent que les gens le pensent, car l'interpréteur Python est vraiment très lent. Dans mon article de blog ici , j'illustre certains profils graphiques qui montrent que même pour des choses très simples, si vous avez affaire à un accès réseau net et rapide à des éléments tels que des bases de données ou des serveurs DNS, ces services peuvent revenir beaucoup plus rapidement que le code Python. peut s'occuper de plusieurs milliers de ces connexions.
la source
C'est assez intéressant pour être analysé. Voici un code pour comparer les performances des greenlets par rapport au pool multitraitement par rapport au multi-threading:
Voici les résultats:
Je pense que greenlet prétend qu'il n'est pas lié par GIL contrairement à la bibliothèque multithreading. De plus, le document Greenlet dit qu'il est destiné aux opérations réseau. Pour une opération réseau intensive, la commutation de threads est très bien et vous pouvez voir que l'approche multithreading est assez rapide. De plus, il est toujours préférable d'utiliser les bibliothèques officielles de python; J'ai essayé d'installer greenlet sur Windows et j'ai rencontré un problème de dépendance dll, j'ai donc exécuté ce test sur une machine virtuelle Linux. Essayez toujours d'écrire un code dans l'espoir qu'il fonctionne sur n'importe quelle machine.
la source
getsockbyname
met en cache les résultats au niveau du système d'exploitation (du moins sur ma machine, c'est le cas). Lorsqu'il est appelé sur un DNS précédemment inconnu ou expiré, il effectuera en fait une requête réseau, ce qui peut prendre un certain temps. Lorsqu'il est appelé sur un nom d'hôte qui vient d'être résolu, il renvoie la réponse beaucoup plus rapidement. Par conséquent, votre méthodologie de mesure est ici défectueuse. Cela explique vos résultats étranges - gevent ne peut pas vraiment être bien pire que le multithreading - les deux ne sont pas vraiment parallèles au niveau de la VM.using_gevent() 421.442985535ms using_multiprocessing() 394.540071487ms using_multithreading() 402.48298645ms