2012-08-10 5 views
5

Aus was ich von tornado.gen Modul Dokumentation verstehe ist, dass tornado.gen.Task umfasst tornado.gen.Callback und tornado.gen.Wait mit jedem Callback/Wait-Paar mit eindeutigen Schlüsseln zugeordnet. ..Tornado Async HTTP Ergebnisse inkrementell zurückgeben

@tornado.web.asynchronous 
    @tornado.gen.engine 
    def get(self): 
     http_client = AsyncHTTPClient() 
     http_client.fetch("http://google.com", 
         callback=(yield tornado.gen.Callback("google"))) 

     http_client.fetch("http://python.org", 
         callback=(yield tornado.gen.Callback("python"))) 

     http_client.fetch("http://tornadoweb.org", 
         callback=(yield tornado.gen.Callback("tornado"))) 
     response = yield [tornado.gen.Wait("google"), tornado.gen.Wait("tornado"), tornado.gen.Wait("python")] 

     do_something_with_response(response) 
     self.render("template.html") 

Also der obige Code wird alle Antworten von den verschiedenen URLs erhalten. Jetzt muss ich eigentlich die Antwort zurückgeben, sobald ein http_client die Daten zurückgibt. Wenn also 'tornadoweb.org' die Daten zuerst zurückgibt, sollte es ein self.write (respose) machen und eine Schleife in def get() sollte warten, bis andere http_clients fertig sind. Irgendwelche Ideen, wie man dies mit tornado.gen Interface schreibt.

Sehr vage Umsetzung (und syntaktisch falsch) von dem, was ich versuche wie diese

class GenAsyncHandler2(tornado.web.RequestHandler): 
    @tornado.web.asynchronous 
    @tornado.gen.engine 
    def get(self): 
     http_client = AsyncHTTPClient() 
     http_client.fetch("http://google.com", 
          callback=(yield tornado.gen.Callback("google"))) 

     http_client.fetch("http://python.org", 
          callback=(yield tornado.gen.Callback("python"))) 

     http_client.fetch("http://tornadoweb.org", 
          callback=(yield tornado.gen.Callback("tornado"))) 

     while True: 
      response = self.get_response() 
      if response: 
       self.write(response) 
       self.flush() 
      else: 
       break 
     self.finish() 


    def get_response(self): 
     for key in tornado.gen.availableKeys(): 
      if key.is_ready: 
       value = tornado.gen.pop(key) 
       return value 
     return None 

Antwort

3

Zusätzlich dazu gibt es tatsächlich ist ein Verfahren WaitAll, die für alle Ergebnisse und kehrt wartet, wenn alle HTTPCliens abgeschlossen haben geben Antworten. Ich habe den Diff in meinem Tornado-Zweig (https://github.com/pranjal5215/tornado) eingereicht. Ich habe eine WaitAny-Klasse hinzugefügt, die Async WaitAll ist und Ergebnis zurückgibt, sobald ein HTTPClient das Ergebnis zurückgegeben hat.

Diff ist (https://github.com/pranjal5215/tornado/commit/dd6902147ab2c5cbf2b9c7ee9a35b4f89b40790e), (https://github.com/pranjal5215/tornado/wiki/Add-WaitAny-to-make-WaitAll-return-results-incrementally)

Verwendungsbeispiel:

class GenAsyncHandler2(tornado.web.RequestHandler): 
    @tornado.web.asynchronous 
    @tornado.gen.engine 
    def get(self): 
     http_client = AsyncHTTPClient() 
     http_client.fetch("http://google.com", 
          callback=(yield tornado.gen.Callback("google"))) 

     http_client.fetch("http://python.org", 
          callback=(yield tornado.gen.Callback("python"))) 

     http_client.fetch("http://tornadoweb.org", 
          callback=(yield tornado.gen.Callback("tornado"))) 
     keys = set(["google", "tornado", "python"]) 
     while keys: 
      key, response = yield tornado.gen.WaitAny(keys) 
      keys.remove(key) 
      # do something with response 
      self.write(str(key)+"  ") 
      self.flush() 
     self.finish() 
4

zu tun, wäre es so ist, wenn man nicht inline callbacks verwenden sollten, das heißt gen. Auch self.render wird aufgerufen, nachdem alle Rückrufe beendet sind. Wenn Sie die Antwort vom Server teilweise zurückgeben möchten - teilweise rendern.

Denken auf diese Weise (es mit großem Raum verbesserungs nur Idee ist):

response = [] 
    @tornado.web.asynchronous 
    def get(self): 
     self.render('head.html') 
     http_client = AsyncHTTPClient() 

     http_client.fetch("http://google.com", 
         callback=self.mywrite) 

     http_client.fetch("http://python.org", 
         callback=self.mywrite) 

     http_client.fetch("http://tornadoweb.org", 
         callback=self.mywrite) 

     self.render('footer.html') 
     self.finish() 


    def mywrite(self, result): 
     self.render('body_part.html') 
     self.response.add(result) 
     if len(self.response) == 3: 
     do_something_with_response(self.response)