我有一个带有以下代码的处理程序:
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没有采用异步功能。
答案 0 :(得分:1)
我希望在处理程序内部,一切都会在等待的
downloader.fetch(request)
行上停止,直到我为返回的Future设置值为止。
你是对的。
但是您的代码有问题。 Keep these points in mind *:
async def
函数或装饰gen.coroutine
的函数)会自动返回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
,或者必须在代码中进行大量更改,则可以忽略此操作。
*披露:链接的文章来自我自己的博客。