龙卷风等待未来对象解决

Tornado await for Future object to resolve

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

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 不采用异步功能。

I was hoping that inside my handler, things will stop on the await downloader.fetch(request) line until I set a value on the returned future.

你是对的。

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

  1. 协程(async def 函数,或 gen.coroutine 装饰函数)自动 return 一个 Future
  2. 你从协程中 return 得到的任何东西,都会被包裹在 Future 中。

async def fetch(request) 函数中,您正在 return 创建一个 Future 对象。但是根据上面的规则 2,您的 Future 对象将被包装在协程的 Future 对象中。

所以,await downloader.fetch 没有暂停你的函数的原因是因为由 fetch 协程自动 returned 的 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,或者如果您必须对代码进行大量更改,则可以忽略它。


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