【问题标题】:why tornado asynchronous doesn't work为什么龙卷风异步不起作用
【发布时间】:2015-04-17 06:32:46
【问题描述】:

今天,当我想让一些同步 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环境下都试过了。

【问题讨论】:

    标签: python asynchronous tornado


    【解决方案1】:

    最后,通过在 URL 末尾添加一些独特的无用参数来解决这个问题。

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

    如果您使用上面的代码测试结果,您将收到与使用同步代码相同的结果(因为 tornado 将返回 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()});
                }
    

    【讨论】:

    • 某些浏览器的限制是它们不会打开多个到同一个 URL 的连接。因此,对于第一个代码示例,浏览器实际上正在执行阻塞。
    • 是的,@AntBlackshaw 是对的。见this similar question
    【解决方案2】:

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

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

    【讨论】:

    • 其实我分别测试了两个handler的结果,在测试YSleepHandler的时候没有调用SleepHandler。但是,最后我得到了result。你能告诉我如何以正确的方式重写这段代码吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多