2010-10-31 7 views
4

Est-il possible d'utiliser les librairies standard de python xmlrpclib avec gevent? Actuellement, je suis tenté d'utiliser monkey.patch_all(), mais sans succès.Utiliser gevent avec python xmlrpclib

from gevent import monkey 
monkey.patch_all() 

import gevent 

import time 

import xmlrpclib 
from SimpleXMLRPCServer import SimpleXMLRPCServer 

import urllib2 

def fetch(url): 
     g = gevent.spawn(urllib2.urlopen, url) 
     return g.get().read() 
def is_even(n): 
    return n%2 == 0 

def req(url): 
     return fetch(url) 

server = SimpleXMLRPCServer(("localhost", 8000)) 
print "Listening on port 8000..." 
server.register_function(is_even, "is_even") 
server.register_function(req, "req") 
server.serve_forever() 

urllib2.urlopen bloque le serveur. Il me semble, que monkey.patch_all n'a pas patché le socket, c'est pourquoi il bloque.

Répondre

9

Le socket est bien corrigé, mais il y a d'autres problèmes avec votre code.

En premier lieu, ce

def fetch(url): 
    g = gevent.spawn(urllib2.urlopen, url) 
    return g.get().read() 

est le même que

def fetch(url): 
    return urllib2.urlopen(url).read() 

Vous fraie un nouveau Greenlet ici mais bloquant l'actuel jusqu'à ce nouveau se fait. Cela ne rend pas les choses concurrentes. C'est exactement la même chose que de lancer urlopen et d'attendre que ça se termine. Deuxièmement, afin de tirer parti de gevent, il devait y avoir plus d'un fil léger (greenlet) fonctionnant en même temps.

SimpleXMLRPCServer, cependant, est définie comme

class SimpleXMLRPCServer(SocketServer.TCPServer, 
         SimpleXMLRPCDispatcher): 

ce qui signifie qu'il dessert une connexion à la fois.

Si vous créez votre propre classe SimpleXMLRPCServer, mais utilisez ThreadingTCPServer au lieu de TCPServer, vous devriez pouvoir bénéficier de l'utilisation de gevent ici.

monkey.patch_all() patches threading pour devenir un greenlet, de sorte que ce serveur génère un nouveau greenlet pour chaque nouvelle connexion.

+0

Merci! La version filetée fonctionne comme prévu! Mais comment retourner le résultat asynchrone de urllib2.urlopen? – frx

+0

Je ne suis pas sûr de comprendre ce que vous entendez par "renvoyer le résultat de manière asynchrone". Qu'essayez-vous d'accomplir? –

+0

Corrigez-moi si je me trompe. Chaque nouvelle connexion est engendrée dans le nouveau greenlet, donc je n'ai pas besoin de lancer urlopen dans le nouveau greenlet. quand urlopen est appelé et s'il y a plus d'une connexion ou qu'un nouvel événement se produit, gevent passe à un autre coroutine, quand le contenu arrive sur le socket, il revient à urlopen coroutine et renvoie le résultat. – frx

Questions connexes