2011-02-10 19 views
11

Ho bisogno di un tipo di funzionalità di callback in Python dove sto inviando una richiesta a un webservice più volte, con una modifica del parametro ogni volta. Voglio che queste richieste avvengano contemporaneamente anziché in modo sequenziale, quindi voglio che la funzione venga chiamata in modo asincrono.Chiamate HTTP asincrone in Python

Sembra che Asyncore sia quello che potrei voler usare, ma gli esempi che ho visto di come funziona sembrano tutti eccessivi, quindi mi chiedo se c'è un altro percorso che dovrei andare giù. Qualche suggerimento su moduli/processo? Idealmente mi piacerebbe usarli in modo procedurale invece di creare classi ma potrei non essere in grado di aggirare il problema.

+0

Overkill di strada. Tutto ciò di cui ho bisogno sono le chiamate http simultanee da uno script (non ho bisogno di chiamare un processo dalla riga di comando, ecc.). Ho semplicemente bisogno di avere funzionalità di callback, ma non riesco a trovare il processo per questo in Python. Ulteriori ricerche mi stanno portando verso urllib2. – kasceled

+1

Overkill? I thread non hanno nulla a che fare con i processi di chiamata dalla riga di comando. – Falmarri

+0

tippytop, sì ovviamente urllib2 per il trasporto .. ma hai ancora bisogno di generarli in parallelo. così puoi fare threading, multiprocessing, concurrent.futures o una soluzione basata su asynch i/o. –

risposta

8

Twisted framework è solo il biglietto per quello. Ma se non vuoi utilizzarlo potresti usare anche pycurl, wrapper per libcurl, che ha il suo loop di eventi asincroni e supporta i callback.

+0

Ho finito per riprendere l'approccio di pycurl quando l'ho postato (mi dispiace per l'accettazione tardiva). – kasceled

+1

@tippytop Cool. Potresti anche essere interessato al mio involucro di semplificazione. Il modulo [pycopia.WWW.client] (http://code.google.com/p/pycopia/source/browse/trunk/WWW/pycopia/WWW/client.py). – Keith

13

A partire da Python 3.2, è possibile utilizzare,per l'avvio di attività parallele.

Partenza questo ThreadPoolExecutor esempio:

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

Si genera discussioni per recuperare HTML e agisce sulle risposte non appena vengono ricevute.

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))) 

L'esempio precedente utilizza la filettatura. V'è anche una simile ProcessPoolExecutor che utilizza un pool di processi, piuttosto che le discussioni:

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

ne sai di eventlet? Ti permette di scrivere quello che sembra essere un codice sincrono, ma farlo funzionare in modo asincrono sulla rete.

Ecco un esempio di un cingolato super-minimal:

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

(Anche se questa discussione è di circa Python lato server Dal momento che questa domanda è stato chiesto un po 'indietro Altri potrebbero incappare in questo, dove stanno cercando.. una risposta simile sul lato client)

Per una soluzione lato client, è possibile dare un'occhiata alla libreria Async.js in particolare alla sezione "Controllo-flusso".

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

Combinando il "parallelo" con una "cascata" è possibile ottenere il risultato desiderato.

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

Se si esamina l'esempio sotto Control-Flow - "Auto" che vi faccia un esempio di quanto sopra: https://github.com/caolan/async#autotasks-callback dove "scrivere -file "dipende da" get_data "e" make_folder "e" email_link "dipende dal file di scrittura".

Si noti che tutto ciò avviene sul lato client (a meno che non si stia facendo Nodo.JS - sul lato server)

Per Python lato server, guarda pycurl @https://github.com/pycurl/pycurl/blob/master/examples/basicfirst.py

Combinando l'esempio di seguito con pycurl, è possibile ottenere la funzionalità non bloccante multi-threaded.

Spero che questo aiuti. In bocca al lupo.

Venkatt @http://MyThinkpond.com

Problemi correlati