2010-08-21 12 views
2

Mon application Gae récupère des données JSON à partir d'un site tiers; Étant donné un ID représentant l'élément à télécharger, les données de l'élément sur ce site sont organisées en plusieurs pages, mon code doit donc télécharger des blocs de données, page après page, jusqu'à ce que les données de la dernière page disponible soient récupérées.
Mon code simplifié ressemble à ceci:Google App Engine: comment paralléliser les téléchargements en utilisant TaskQueue ou Async Urlfetch?

class FetchData(webapp.RequestHandler): 
    def get(self): 
    ... 
    data_list = [] 
    page = 1 
    while True: 
     fetched_data= urlfetch.fetch('http://www.foo.com/getdata?id=xxx&result=JSON&page=%s' % page) 
     data_chunk = fetched_data["data"] 
     data_list = data_list + data_chunk 
     if len(data_list) == int(fetched_data["total_pages"]): 
     break 
     else: 
     page = page +1 
    ... 
    doRender('dataview.htm',{'data_list':data_list}) 

Les résultats data_list est une liste ordonnée où le premier élément a données du numéro de page 1 et le dernier élément a données de la dernière pages; ce data_list, une fois récupéré, est rendu dans une vue.

Cette approche fonctionne 99% des cas, mais parfois, en raison de la 30 secondes limite imposée par Google App Engine, sur des articles de plusieurs pages que je reçois la DeadlineExceededError redoutée. Je voudrais savoir si vous utilisez TaskQueue | Deferred | AsyncUrlfetch Je pourrais améliorer cet algorithme parallélisant en quelque sorte les N appels urlfetch.

+0

Laissez-moi savoir si la solution fonctionne ci-dessous pour vous –

+0

avez vous avez eu de la chance? –

Répondre

1

Utilisez ceci: http://code.google.com/appengine/docs/python/urlfetch/asynchronousrequests.html

Ce qui est simple comme ceci:

def handle_result(rpc): 
    result = rpc.get_result() 
    # ... Do something with result... 

# Use a helper function to define the scope of the callback. 
def create_callback(rpc): 
    return lambda: handle_result(rpc) 

rpcs = [] 
for url in urls: 
    rpc = urlfetch.create_rpc() 
    rpc.callback = create_callback(rpc) 
    urlfetch.make_fetch_call(rpc, url) 
    rpcs.append(rpc) 

# ... 

# Finish all RPCs, and let callbacks process the results. 
for rpc in rpcs: 
    rpc.wait() 
+0

c'est bien où c'est. il suffit de remplacer la section while par le code ci-dessus et de modifier si nécessaire. pas de globals nécessaire. –

+1

Bien que pas très détaillé, votre réponse m'a aidé à me concentrer sur la solution asynchrone. – systempuntoout

0

J'ai résolu avec ceci:

chunks_dict = {} 

def handle_result(rpc, page): 
    result = rpc.get_result() 
    chunks_dict[page] = result["data"] 

def create_callback(rpc, page): 
    return lambda: handle_result(rpc, page) 

rpcs = [] 
while True: 
    rpc = urlfetch.create_rpc(deadline = 10) 
    rpc.callback = create_callback(rpc, page) 
    urlfetch.make_fetch_call(rpc, 'http://www.foo.com/getdata?id=xxx&result=JSON&page=%s' % page) 
    rpcs.append(rpc) 
    if page > total_pages: 
     break 
    else: 
     page = page +1 
for rpc in rpcs: 
    rpc.wait() 

page_keys = chunks_dict.keys() 
page_keys.sort() 
for key in page_keys: 
    data_list= data_list + chunks_dict[key]