2011-02-10 26 views
11

Necesito un tipo de funcionalidad de devolución de llamada en Python, donde estoy enviando una solicitud a un servicio web varias veces, con un cambio en el parámetro cada vez. Quiero que estas solicitudes sucedan simultáneamente en lugar de secuencialmente, por lo que quiero que la función se llame de forma asíncrona.Llamadas HTTP asíncronas en Python

Parece que asyncore es lo que podría querer usar, pero los ejemplos que he visto de cómo funciona todo lo ven como una exageración, por lo que me pregunto si hay otro camino que debería ir hacia abajo. ¿Alguna sugerencia sobre módulos/proceso? Idealmente, me gustaría utilizarlos de forma procedimental en lugar de crear clases, pero es posible que no pueda evitarlos.

+0

Overkill excesivo. Todo lo que necesito son llamadas http simultáneas desde un script (no necesito llamar a un proceso desde la línea de comandos, etc.). Simplemente necesito tener funcionalidad de devolución de llamada, pero no puedo encontrar el proceso para esto en Python. La investigación adicional me está conduciendo hacia urllib2. – kasceled

+1

Overkill? Los hilos no tienen nada que ver con los procesos de llamada desde la línea de comandos. – Falmarri

+0

tippytop, sí, por supuesto, urllib2 para el transporte ... pero aún necesita generarlos en paralelo. para que pueda hacer threading, multiprocesamiento, concurrent.futures o una solución basada en i/o asincrónica. –

Respuesta

8

Twisted framework es el boleto para eso. Pero si no desea hacerlo, también puede usar pycurl, wrapper para libcurl, que tiene su propio bucle de evento asíncrono y admite devoluciones de llamada.

+0

Terminé tomando el enfoque pycurl cuando publiqué esto (lo siento por la aceptación tardía). – kasceled

+1

@tippytop Cool. También podría estar interesado en mi envoltorio de simplificación además de eso. El módulo [pycopia.WWW.client] (http://code.google.com/p/pycopia/source/browse/trunk/WWW/pycopia/WWW/client.py). – Keith

13

Comenzando en Python 3.2, puede usar concurrent.futures para iniciar tareas paralelas.

Control hacia fuera este ThreadPoolExecutor ejemplo:

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

Se genera subprocesos para recuperar HTML y actúa sobre 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 el enhebrado. También hay un parecido ProcessPoolExecutor que utiliza un conjunto 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))) 
16

¿Conoce acerca eventlet? Te permite escribir lo que parece ser un código sincrónico, pero que funcione de forma asíncrona a través de la red.

He aquí un ejemplo de un rastreador súper mínima:

urls = ["http://www.google.com/intl/en_ALL/images/logo.gif", 
    "https://wiki.secondlife.com/w/images/secondlife.jpg", 
    "http://us.i1.yimg.com/us.yimg.com/i/ww/beta/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) 
0

(Aunque este hilo es sobre Python en el servidor Dado que esta pregunta se hizo hace un tiempo Otros podrían tropezar en este donde se están buscando.. 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

Al combinar el "paralelo" con una "cascada" que puede lograr el resultado deseado.

Cascada (Paralelo (Taska, TaskB, TaskC) -> PostParallelTask)

Si examina el ejemplo bajo control de flujo - "Auto" que le dan un ejemplo de lo anterior: https://github.com/caolan/async#autotasks-callback donde "escribir -file "depende de" get_data "y" make_folder "y" email_link "depende de write-file".

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

de Python para el lado del servidor, mira a pycurl @https://github.com/pycurl/pycurl/blob/master/examples/basicfirst.py

Al combinar el siguiente ejemplo con pycurl, se puede lograr la funcionalidad de no bloqueo multi-hilo.

Espero que esto ayude. Buena suerte.

Venkatt @http://MyThinkpond.com

Cuestiones relacionadas