2011-02-10 8 views
11

j'ai besoin d'une sorte de fonctionnalité de rappel en Python où je vous envoie une demande à un webservice plusieurs fois, avec une modification du paramètre à chaque fois. Je veux que ces demandes se produisent simultanément au lieu de séquentiellement, donc je veux que la fonction soit appelée de manière asynchrone.appels HTTP asynchrone en Python

Il semble que ce que je pourrais utiliser, c'est l'asyncore, mais les exemples que j'ai vus de comment cela fonctionne semblent tous exagérés, donc je me demande s'il y a un autre chemin que je devrais descendre. Des suggestions sur les modules/processus? Idéalement, j'aimerais les utiliser de façon procédurale plutôt que de créer des cours, mais je ne serai peut-être pas en mesure de contourner ce problème.

+0

De manière excessive. Tout ce dont j'ai besoin, ce sont des appels HTTP simultanés depuis un script (je n'ai pas besoin d'appeler un processus depuis la ligne de commande, etc). J'ai simplement besoin d'une fonctionnalité de rappel, mais je ne trouve pas le processus pour cela en python. D'autres recherches me mènent vers urllib2. – kasceled

+1

Overkill? Les threads n'ont rien à voir avec l'appel de processus à partir de la ligne de commande. – Falmarri

+0

tippytop, oui bien sûr urllib2 pour le transport .. mais vous avez encore besoin de les engendrer en parallèle. Vous pouvez donc faire du threading, du multiprocessing, du concurrent.futures ou une solution basée sur les E/S asynch. –

Répondre

8

Twisted framework est juste le billet pour cela. Mais si vous ne voulez pas prendre cela, vous pouvez aussi utiliser pycurl, wrapper pour libcurl, qui a sa propre boucle d'événement asynchrone et supporte les callbacks.

+0

J'ai fini par reprendre l'approche pycurl quand j'ai posté ceci (désolé pour l'acceptation tardive). – kasceled

+1

@tippytop Cool. Vous pourriez également être intéressé par mon emballage simplificateur en plus de cela. Le module [pycopia.WWW.client] (http://code.google.com/p/pycopia/source/browse/trunk/WWW/pycopia/WWW/client.py). – Keith

13

À partir de Python 3.2, vous pouvez utiliser concurrent.futures pour lancer des tâches parallèles.

Vérifiez cette exemple ThreadPoolExecutor:

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

Il engendre des fils pour récupérer HTML et agit sur les réponses qu'ils sont reçus.

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'exemple ci-dessus utilise le filetage. Il y a aussi un ProcessPoolExecutor similaire qui utilise un pool de processus, plutôt que des fils:

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

Connaissez-vous eventlet? Il vous permet d'écrire ce qui semble être du code synchrone, mais de le faire fonctionner de manière asynchrone sur le réseau.

Voici un exemple d'un robot 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

(Bien que ce fil est de Python côté serveur Comme cette question a été posée un certain temps D'autres pourraient tomber par hasard sur ce où qu'ils recherchent.. une réponse similaire sur le côté client)

pour une solution côté client, vous voudrez peut-être jeter un oeil à la bibliothèque Async.js en particulier la section « contrôle-Flow ».

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

En combinant le « parallèle » avec une « cascade », vous pouvez obtenir le résultat souhaité.

WaterFall (parallèle (Taska, TaskB, TaskC) -> PostParallelTask)

Si vous examinez l'exemple de contrôle-Flow - "Auto" ils vous donnent un exemple de ce qui précède: https://github.com/caolan/async#autotasks-callback où « écrire -file "dépend de" get_data "et" make_folder "et" email_link "dépend du fichier d'écriture"

Veuillez noter que tout cela se passe côté client (à moins que vous ne fassiez un noeud.JS - sur le côté serveur)

Pour Python côté serveur, regardez pycurl @https://github.com/pycurl/pycurl/blob/master/examples/basicfirst.py

En combinant l'exemple ci-dessous avec pycurl, vous pouvez obtenir la fonctionnalité multi-thread non-bloquant.

Espérons que cela aide. Bonne chance.

Venkatt @http://MyThinkpond.com