2012-08-10 105 views
5

從我從tornado.gen模塊docs中瞭解到的是,tornado.gen.Task包含tornado.gen.Callback和tornado.gen.Wait,每個Callback/Wait對與唯一鍵相關聯。 ...Tornado異步HTTP遞歸返回結果

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

因此,上面的代碼將獲得來自不同URL的所有響應。 現在我真正需要做的是在一個http_client返回數據後立即返回響應。因此,如果'tornadoweb.org'首先返回數據,它應該執行self.write(respose)並且def get()中的循環應該繼續等待其他http_client完成。 有關如何使用tornado.gen接口編寫此任何想法。

的什麼,我試圖做會是這樣

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 

回答

3

除此之外,其實還有一種方法爲WaitAll當所有HTTPCliens已經完成了給它等待所有的結果和回報響應。 我在龍捲風分支中提交了差異(https://github.com/pranjal5215/tornado)。我添加了一個WaitAny類,它是異步WaitAll,並在一個HTTPClient返回結果後立即返回結果。

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

示例用法:

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

它的情況下,當你不應該使用inline callbacks,即gen很模糊的實現(語法不正確)。 還將在所有回調完成後調用self.render如果您想部分返回來自服務器的響應。

這樣的想法(這是隻有大房間的改進意見):

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)