gpt4 book ai didi

python - 为什么异步和 gen.coroutine 的顺序在 Tornado 中很重要?

转载 作者:太空宇宙 更新时间:2023-11-04 03:39:11 25 4
gpt4 key购买 nike

我有一段代码如下:

@tornado.web.stream_request_body
class DownloadHandler(SecureHandler):
executor = ThreadPoolExecutor(50)

@tornado.web.authenticated
@tornado.gen.coroutine
@tornado.gen.asynchronous
def post(self):
# ...

path = yield self.down_load(fname)

self.set_header("Content-Type", "application/octet-stream")
self.set_header("Content-Disposition", "attachment;filename=%s" % fname)

self.generator = self.read_file(path)
tornado.ioloop.IOLoop.instance().add_callback(self.loop)

@run_on_executor
def down_load(self, fname):
# download a file named `fname` from other website
# store it in a temp file at `path`
# ...
return path

def loop(self):
try:
data = self.generator.next()
self.write(data)
self.flush()
tornado.ioloop.IOLoop.instance().add_callback(self.loop)
except Exception as e:
traceback.print_exc()
self.finish()

def read_file(self, fname):
with open(fname, 'rb') as f:
while True:
data = f.read(1024 * 1024 * 8)
if not data
break
yield data

如果 asynchronous 和 gen.coroutine 的顺序如我的代码所示,则可以正常工作。

但是如果我调换它们的顺序,客户端只能收到8MB的数据。 traceback.print_exc() 打印 finish() 调用了两次。可能是由于在没有@asynchronous 装饰器的情况下使用异步操作导致的

那么我的问题是,为什么这两个装饰器的顺序很重要,选择顺序的规则是什么?

最佳答案

顺序很重要,因为 @asynchronous 查看 @gen.coroutine 返回的 Future,并调用 finish当协程返回时为您服务。自 Tornado 3.1 以来,@asynchronous@gen.coroutine 的组合已不再必要,也不鼓励;在大多数情况下,您应该单独使用 @gen.coroutine

但是,您在此处展示的示例有点奇怪 - 它以不太有效的方式混合了协程和回调样式。协程在完成之前返回,并将剩余的工作留给回调链。这实际上类似于 @asynchronous 装饰器对非协程函数所做的事情,尽管它不适用于两个装饰器之间的交互。这里最好的解决方案是使 loop() 也成为协程:

@gen.coroutine
def loop(self):
for data in self.generator:
self.write(data)
yield self.flush()

然后你可以用yield self.loop()调用它,协程就可以正常工作了。您不再需要显式调用 finish(),或使用 @asynchronous 装饰器。

关于python - 为什么异步和 gen.coroutine 的顺序在 Tornado 中很重要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27393059/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com