Llamadas HTTP asíncronas en Python

Necesito un tipo de funcionalidad de callback en Python donde envío una solicitud a un servicio web varias veces, con un cambio en el parámetro cada vez. Quiero que estas solicitudes se realicen de forma concurrente en lugar de secuencial, por lo que quiero que la función se llame de forma asíncrona.

Parece que lo que querría usar es asyncore, pero los ejemplos que he visto de cómo funciona parecen exagerados, así que me pregunto si hay otro camino que debería seguir. ¿Alguna sugerencia sobre módulos / proceso? Idealmente, me gustaría usarlos de manera procedimental en lugar de crear clases, pero es posible que no pueda evitarlo.

El marco retorcido es el boleto para eso. Pero si no quiere usar eso , también puede usar pycurl , envoltura para libcurl, que tiene su propio bucle de eventos asíncronos y es compatible con devoluciones de llamada.

¿Sabes de eventlet ? Le permite escribir lo que parece ser un código síncrono, pero hacer que funcione de forma asíncrona a través de la red.

Aquí hay un ejemplo de un rastreador super minimal:

urls = ["http://sofes.miximages.com/python/logo.gif", "https://wiki.secondlife.com/w/images/secondlife.jpg", "http://sofes.miximages.com/python/y3.gif"] import eventlet from eventlet.green import urllib2 def fetch(url): return urllib2.urlopen(url).read() pool = eventlet.GreenPool() for body in pool.imap(fetch, urls): print "got body", len(body) 

A partir de Python 3.2, puede usar concurrent.futures para iniciar tareas paralelas.

Echa un vistazo a este ejemplo ThreadPoolExecutor :

http://docs.python.org/dev/library/concurrent.futures.html#threadpoolexecutor-example

Genera hilos para recuperar HTML y actúa sobre las respuestas a medida que se reciben.

 import concurrent.futures import urllib.request URLS = ['http://www.foxnews.com/', 'http://www.cnn.com/', 'http://europe.wsj.com/', 'http://www.bbc.co.uk/', 'http://some-made-up-domain.com/'] # Retrieve a single page and report the url and contents def load_url(url, timeout): conn = urllib.request.urlopen(url, timeout=timeout) return conn.readall() # We can use a with statement to ensure threads are cleaned up promptly with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: # Start the load operations and mark each future with its URL future_to_url = {executor.submit(load_url, url, 60): url for url in URLS} for future in concurrent.futures.as_completed(future_to_url): url = future_to_url[future] try: data = future.result() except Exception as exc: print('%r generated an exception: %s' % (url, exc)) else: print('%r page is %d bytes' % (url, len(data))) 

El ejemplo anterior utiliza subprocesos. También hay un ProcessPoolExecutor similar que usa un grupo de procesos, en lugar de hilos:

http://docs.python.org/dev/library/concurrent.futures.html#processpoolexecutor-example

 import concurrent.futures import urllib.request URLS = ['http://www.foxnews.com/', 'http://www.cnn.com/', 'http://europe.wsj.com/', 'http://www.bbc.co.uk/', 'http://some-made-up-domain.com/'] # Retrieve a single page and report the url and contents def load_url(url, timeout): conn = urllib.request.urlopen(url, timeout=timeout) return conn.readall() # We can use a with statement to ensure threads are cleaned up promptly with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: # Start the load operations and mark each future with its URL future_to_url = {executor.submit(load_url, url, 60): url for url in URLS} for future in concurrent.futures.as_completed(future_to_url): url = future_to_url[future] try: data = future.result() except Exception as exc: print('%r generated an exception: %s' % (url, exc)) else: print('%r page is %d bytes' % (url, len(data))) 

(Aunque este hilo trata sobre Python del lado del servidor. Dado que esta pregunta se hizo hace un tiempo atrás, otros podrían tropezar con esto cuando buscan una respuesta similar en el lado del cliente)

Para una solución del lado del cliente, es posible que desee echar un vistazo a la biblioteca Async.js, especialmente la sección “Control-Flow”.

https://github.com/caolan/async#control-flow

Combinando el “Paralelo” con una “Cascada” puede lograr el resultado deseado.

WaterFall (paralelo (TaskA, TaskB, TaskC) -> PostParallelTask)

Si examinas el ejemplo en Control-Flow, “Auto” te da un ejemplo de lo anterior: https://github.com/caolan/async#autotasks-callback donde “write-file” depende de “get_data” y make_folder “y” email_link “dependen del archivo de escritura”.

Tenga en cuenta que todo esto sucede en el lado del cliente (a menos que esté haciendo Node.JS – en el lado del servidor)

Para Python del lado del servidor, consulte PyCURL @ https://github.com/pycurl/pycurl/blob/master/examples/basicfirst.py

Al combinar el siguiente ejemplo con pyCurl, puede lograr la funcionalidad de subprocesos múltiples sin locking.

Espero que esto ayude. Buena suerte.

Venkatt @ http://MyThinkpond.com