Peticiones de Python con multiproceso.
multithreading asynchronous (1)
Instale el módulo grequests
que funciona con gevent
(las requests
no están diseñadas para async):
pip install grequests
Luego cambia el código a algo como esto:
import grequests
class Test:
def __init__(self):
self.urls = [
''http://www.example.com'',
''http://www.google.com'',
''http://www.yahoo.com'',
''http://www.stackoverflow.com/'',
''http://www.reddit.com/''
]
def exception(self, request, exception):
print "Problem: {}: {}".format(request.url, exception)
def async(self):
results = grequests.map((grequests.get(u) for u in self.urls), exception_handler=self.exception, size=5)
print results
test = Test()
test.async()
Esto es oficialmente recomendado por el proyecto de requests
:
¿Bloqueo o no bloqueo?
Con el adaptador de transporte predeterminado en su lugar, las solicitudes no proporcionan ningún tipo de E / S sin bloqueo. La propiedad
Response.content
se bloqueará hasta que se haya descargado la respuesta completa. Si necesita más granularidad, las funciones de transmisión de la biblioteca (consulte Solicitudes de transmisión por secuencias) le permiten recuperar cantidades más pequeñas de la respuesta a la vez. Sin embargo, estas llamadas seguirán bloqueando.Si le preocupa el uso del bloqueo de E / S, hay muchos proyectos que combinan Solicitudes con uno de los marcos de trabajo asíncrónicos de Python. Dos ejemplos excelentes son las
requests-futures
grequests
y lasrequests-futures
grequests
.
El uso de este método me da un notable aumento de rendimiento con 10 URL: 0.877s
frente a 3.852s
con su método original.
He estado tratando de construir un raspador con funcionalidad de multihilo en los últimos dos días. De alguna manera todavía no podía manejarlo. Al principio intenté un enfoque de subprocesos múltiples con el módulo de subprocesamiento, pero no fue más rápido que usar un solo subproceso. Más tarde, supe que las solicitudes están bloqueando y el enfoque de subprocesamiento múltiple no está funcionando. Así que seguí investigando y descubrí las misiones y gevent. Ahora estoy ejecutando pruebas con gevent y todavía no es más rápido que usar un solo hilo. ¿Está mal mi codificación?
Aquí está la parte relevante de mi clase:
import gevent.monkey
from gevent.pool import Pool
import requests
gevent.monkey.patch_all()
class Test:
def __init__(self):
self.session = requests.Session()
self.pool = Pool(20)
self.urls = [...urls...]
def fetch(self, url):
try:
response = self.session.get(url, headers=self.headers)
except:
self.logger.error(''Problem: '', id, exc_info=True)
self.doSomething(response)
def async(self):
for url in self.urls:
self.pool.spawn( self.fetch, url )
self.pool.join()
test = Test()
test.async()