龙卷风等待未来的对象解决

时间:2018-06-20 19:09:38

标签: python async-await tornado

我有一个带有以下代码的处理程序:

class HelloHandler(RequestHandler):

      routing_pattern = "/hello"

      async def get(self):

          url = 'some_url_here'
          request = httpclient.HTTPRequest(url=url, streaming_callback=self.on_chunk)
          result = await downloader.fetch(request)
          print(result)
          self.write("done")


      @gen.coroutine
      def on_chunk(self, chunk):
          self.write(chunk)
          yield self.flush()

此代码调用如下定义的异步def函数:

async def fetch(request):
    future = Future()
    await _qin.put(request)
    return future

我希望在处理程序内部,一切都将在await downloader.fetch(request)行上停止,直到我在返回的future上设置一个值。现在永远不会发生,所以事情应该就此止步。但是,似乎没有真正等待未来。 print(result)行显示一个“”,并且速度很快超过该行。我究竟做错了什么 ?我如何才能使功能停止在那儿,然后实际上等待将来完成?附带问题...我在on_chunk方法中做什么是正确的?我希望在那里等待刷新,但是streaming_callback没有采用异步功能。

1 个答案:

答案 0 :(得分:1)

  

我希望在处理程序内部,一切都会在等待的downloader.fetch(request)行上停止,直到我为返回的Future设置值为止。

你是对的。

但是您的代码有问题。 Keep these points in mind *:

  1. 协程(async def函数或装饰gen.coroutine的函数)会自动返回Future
  2. 您从协程返回的任何物品都将包裹在Future中。

async def fetch(request)函数中,您将返回Future对象。但是按照上面的规则2,您的Future对象将被包装在协程的Future对象中。

因此,await downloader.fetch不会暂停您的功能的原因是因为fetch协程自动返回的Future即将得到解决。

两次等待​​ 您的代码应该可以正常工作:

result_future = await downloader.fetch(request)
result = await result_future

我个人认为双精度await与一般约定不符。因此,我要做的是使fetch(request)成为常规函数,而不是协程:

def fetch(request):
    future = Future()
    # instead of running _qin.put yourself, 
    # ask the ioloop to run it
    ioloop.IOLoop.current().add_callback(_qin.put, request)
    return future

如果您愿意使用双await,或者必须在代码中进行大量更改,则可以忽略此操作。


*披露:链接的文章来自我自己的博客。