2012-08-10 18 views
5

Por lo que entiendo de los documentos del módulo tornado.gen es que tornado.gen.Task compone de tornado.gen.Callback y tornado.gen.Wait con cada par de devolución de llamada/espera asociada con claves únicas. ..Tornado asincrónicos HTTP devolver resultados incrementalmente

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

Así que el código anterior obtendrá todas las respuestas de las diferentes URL. Ahora lo que realmente tengo que lograr es devolver la respuesta tan pronto como uno http_client devuelve los datos. Así que si 'tornadoweb.org' devuelve los datos en primer lugar, se debe hacer un self.write (respose) y un bucle en def get() debe seguir esperando otros http_clients para completar. Cualquier ideas sobre cómo escribir utilizando esta interfaz tornado.gen.

aplicación muy vaga (y sintácticamente incorrecta) de lo que estoy tratando de hacer esto sería como

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 

Respuesta

3

Además de esto, en realidad no es un método WaitAll el que espera a que todos los resultados y rendimientos cuando todos HTTPCliens han completado dando respuestas. he presentado el diff en mi rama de tornado (https://github.com/pranjal5215/tornado). He agregado una clase WaitAny que es asincrónica WaitAll y devuelve el resultado tan pronto como un HTTPClient ha devuelto el resultado.

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

uso

muestra:

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

Es el caso, cuando no se debe utilizar inline callbacks, es decir gen. También self.render se llamará después de que todas las devoluciones de llamada terminado. Si desea devolver la respuesta del servidor parcialmente, renderícela parcialmente.

pensar de esta manera (es sólo idea con gran sala de mejora):

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)