首页 > 解决方案 > 龙卷风等待未来对象解决

问题描述

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

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()

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

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

我希望在我的处理程序中,事情会在 await downloader.fetch(request) 行停止,直到我为返回的未来设置一个值。现在这永远不会发生,所以事情应该停在那里。然而,似乎并没有真正期待未来。print(result) 行显示一个“”,并且事情只是通过该行加速。我究竟做错了什么 ?我怎样才能让功能停在那里并真正等待未来完成?一个附带问题......我在 on_chunk 方法中所做的是否正确?我想在那里等待刷新,但 streaming_callback 不采用异步函数。

标签: pythonasync-awaittornado

解决方案


我希望在我的处理程序中,事情会在等待downloader.fetch(request)行上停止,直到我为返回的未来设置一个值。

你说的对。

但是你的代码有问题。请记住以下几点*:

  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

如果您对使用 double 感到满意await,或者您必须对代码进行大量更改,则可以忽略这一点。


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


推荐阅读