2012-02-29 17 views
16

para este código:cómo habilitar las solicitudes modo asíncrono?

import sys 

import gevent 
from gevent import monkey 

monkey.patch_all() 

import requests 
import urllib2 

def worker(url, use_urllib2=False): 
    if use_urllib2: 
     content = urllib2.urlopen(url).read().lower() 
    else: 
     content = requests.get(url, prefetch=True).content.lower() 
    title = content.split('<title>')[1].split('</title>')[0].strip() 

urls = ['http://www.mail.ru']*5 

def by_requests(): 
    jobs = [gevent.spawn(worker, url) for url in urls] 
    gevent.joinall(jobs) 

def by_urllib2(): 
    jobs = [gevent.spawn(worker, url, True) for url in urls] 
    gevent.joinall(jobs) 

if __name__=='__main__': 
    from timeit import Timer 
    t = Timer(stmt="by_requests()", setup="from __main__ import by_requests") 
    print 'by requests: %s seconds'%t.timeit(number=3) 
    t = Timer(stmt="by_urllib2()", setup="from __main__ import by_urllib2") 
    print 'by urllib2: %s seconds'%t.timeit(number=3) 
    sys.exit(0) 

este resultado:

by requests: 18.3397213892 seconds 
by urllib2: 2.48605842363 seconds 

en sniffer se ve esto:

Descripción: 5 primeras solicitudes se sended por la biblioteca peticiones, próximos 5 solicitudes son enviado por la biblioteca urllib2. rojo - es el momento en que el trabajo fue congelado, oscuro - cuando se reciben los datos ... wtf ?!

¿Cómo es posible si la biblioteca de socket parcheada y las bibliotecas deben funcionar de forma idéntica? ¿Cómo se utilizan las solicitudes sin requests.async para el trabajo asincrónico?

+0

Puede explicar su problema un poco más lejos? ¿Por qué no quieres usar el módulo requests.async? – Phani

+0

Las solicitudes no funcionan de manera asincrónica. ¿Por qué? No quiero usar requests.async porque contiene una mala interfaz para usar y tampoco funciona asincrónica. Mire la imagen, se ve cómo solicitudes de trabajo y urllib2. – user1239798

+1

Ver http://stackoverflow.com/questions/9110593/asynchronous-requests-with-python-requests y https://github.com/kennethreitz/grequests. –

Respuesta

14

Lo sentimos Kenneth Reitz. Su biblioteca es maravillosa.

Soy estúpido. Necesito un parche de mono para httplib como este:

gevent.monkey.patch_all(httplib=True) 

Porque el parche para httplib está deshabilitado por defecto.

+11

Ya no es válido: ValueError: gevent.httplib ya no se proporciona, httplib debe ser False – mamcx

+1

Usar grequests (por @KennethReitz). En su mayoría anula los verbos principales y hereda el resto. –

2

Corrí su código en mi máquina (python 2.7.1, gevent 0.13.0, requests 0.10.6). Resultó que el tiempo siempre era un buen segundo o dos más rápido cuando se usaba el módulo de solicitudes. ¿Qué versiones estás usando? Una actualización podría simplemente resolver el problema por usted.

by requests: 3.7847161293 seconds 
by urllib2: 4.92611193657 seconds 

by requests: 2.90777993202 seconds 
by urllib2: 7.99798607826 seconds 
+0

Estoy usando estas versiones: python 2.7.2.5, gevent 0.13.6, solicitudes 0.10.6 – user1239798

+0

Sus versiones son aún más avanzadas, por lo que es realmente extraño. He publicado otra respuesta que podría ayudarte. – Phani

7

Como se ha señalado por Kenneth, otra cosa que podemos hacer es dejar que el módulo de requests manejan la parte asíncrona. He hecho cambios a tu código en consecuencia. De nuevo, para mí, los resultados muestran consistentemente que el módulo requests tiene un mejor rendimiento que urllib2

Hacer esto significa que no podemos "enhebrar" la parte de devolución de llamada. Pero eso debería estar bien, porque la ganancia mayor solo debería esperarse con las solicitudes HTTP debido a la demora de solicitud/respuesta.

import sys 

import gevent 
from gevent import monkey 

monkey.patch_all() 

import requests 
from requests import async 
import urllib2 

def call_back(resp): 
    content = resp.content 
    title = content.split('<title>')[1].split('</title>')[0].strip() 
    return title 

def worker(url, use_urllib2=False): 
    if use_urllib2: 
     content = urllib2.urlopen(url).read().lower() 
     title = content.split('<title>')[1].split('</title>')[0].strip() 

    else: 
     rs = [async.get(u) for u in url] 
     resps = async.map(rs) 
     for resp in resps: 
      call_back(resp) 

urls = ['http://www.mail.ru']*5 

def by_requests(): 
    worker(urls) 
def by_urllib2(): 
    jobs = [gevent.spawn(worker, url, True) for url in urls] 
    gevent.joinall(jobs) 

if __name__=='__main__': 
    from timeit import Timer 
    t = Timer(stmt="by_requests()", setup="from __main__ import by_requests") 
    print 'by requests: %s seconds'%t.timeit(number=3) 
    t = Timer(stmt="by_urllib2()", setup="from __main__ import by_urllib2") 
    print 'by urllib2: %s seconds'%t.timeit(number=3) 
    sys.exit(0) 

Aquí está uno de mis resultados:

by requests: 2.44117593765 seconds 
by urllib2: 4.41298294067 seconds 
+0

¡Hola! Gracias por interesarme por mi problema. He ejecutado tu código y he actualizado la imagen de la primera publicación para mostrar cómo funciona tu código. – user1239798

+0

Esto es resultados del trabajo: por pedidos: 25.532893147 segundos por urllib2: 9.65230888283 segundos – user1239798

+0

Me temo que no puedo replicar su problema. Actualicé gevent a 0.13.6 y lo probé en dos máquinas diferentes. Pero el módulo 'requests' funcionaba de forma asíncrona. FYI, lo probé en Ubuntu 11.04 y 11.10. – Phani

Cuestiones relacionadas