为什么龙卷风异步不起作用

why tornado asynchronous doesn't work

今天,当我想使一些同步 Python 库异步运行时,但它不起作用。经过一系列的测试,我发现即使是yield tornado.gen.sleep(N)也能同步运行。

这是我的代码:

import time
import tornado.web
import tornado.gen
import tornado.ioloop
import os


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("test.htm")


class SleepHandler(tornado.web.RequestHandler):
    def get(self):
        time.sleep(2)
        self.write("Good morning!")


class YSleepHandler(tornado.web.RequestHandler):
    @tornado.gen.coroutine
    def get(self):
        yield tornado.gen.sleep(2)
        self.write("Good morning!")


def main():
    app = tornado.web.Application([
        (r"/sleep", SleepHandler),
        (r"/ysleep", YSleepHandler),
        (r"/", MainHandler),
        ], debug=True, template_path=os.path.split(
            os.path.realpath(__file__))[0])
    app.listen(8888)
    try:
        tornado.ioloop.IOLoop.current().start()
    except:
        tornado.ioloop.IOLoop.current().stop()


if __name__ == "__main__":
    main()

我使用下面的代码来测试异步函数是否有效(在 test.htm -- MainHandler 的模板文件中):

for(var i = 0; i < 10; i++){
                $.get("/sleep");
            }
for(var i = 0; i < 10; i++){
                $.get("/ysleep");
            }

但最后,我得到了意想不到的结果result

怎么了?我在 Python2.7 和 Python3.4 环境下都试过了。

您看到此行为是因为协程中的 yield 有效地将控制权转移回 Tornado 的 IOLoop。这并不意味着它 returns 是客户端的结果 - 只是它 returns 控制了 Tornado,这样 IOLoop 就不会被长 运行 请求阻塞。

这对您的代码的影响是 Tornado 将在 SleepHandler 运行时阻塞,而在 YSleepHandler 运行时它不会阻塞。在这两种情况下,仅当您的处理程序调用 self.write() 时,响应才会返回给客户端,但在 YSleepHandler 的情况下,当处理程序被调用时,其他请求可以得到服务运行 因为 IOLoop 没有被阻塞。

最后,通过在 URL.

的末尾添加一些独特的无用参数,这个问题得到了解决。
for(var i = 0; i < 10; i++){
                $.get("/sleep");
            }
for(var i = 0; i < 10; i++){
                $.get("/ysleep");
            }

如果您使用上面的代码来测试结果,您将收到与使用同步代码相同的结果(因为 tornado 将 return 304 未修改,它是一个同步函数。)。但是如果使用下面的代码,同步和异步之间的区别将被完全说明。

for(var i = 0; i < 10; i++){
                $.get("/sleep", {"random": Math.random()});
            }
for(var i = 0; i < 10; i++){
                $.get("/ysleep", {"random": Math.random()});
            }