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

标签 python asynchronous tornado decorator coroutine

我有一段代码如下:

@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

如果异步和 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/

相关文章:

python - Matplotlib Canvas 绘图

python - 使用 networkx 计算特征向量中心性

javascript - Node.js 异步函数未被识别为有效的异步函数

python - Tornado https ssl 错误

python HTTP 599 : Connection closed (Tornado)

python - Tornado官方canonical "Hello, world"example app报错怎么解决?

python - 从 String 在 python 中写入 TIFF 文件

python - 无法在 pygal 折线图中设置宽度和高度

java - 为什么 ExecutorService 等待所有线程完成而 Completablefuture 不等待?

python - 信号和 django channel 聊天室