今天,当我想让一些同步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环境下都尝试过。
答案 0 :(得分:1)
最后,通过在URL的末尾添加一些独特的无用参数来重新解决这个问题。
for(var i = 0; i < 10; i++){
$.get("/sleep");
}
for(var i = 0; i < 10; i++){
$.get("/ysleep");
}
如果您使用上面的代码测试结果,您将收到与使用同步代码相同的结果(因为龙卷风将返回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()});
}
答案 1 :(得分:0)
您看到此行为是因为协程中的 yield 有效地将控制权转移回Tornado的IOLoop。这并不意味着它将结果返回给客户端 - 只是它将控制权返回给Tornado,以便IOLoop不会被长时间运行的请求阻止。
这对你的代码产生的影响是Tornado会在SleepHandler运行时阻塞,而在YSleepHandler运行时它不会阻塞。在这两种情况下,仅当您的处理程序调用 self.write()时,响应才会返回给客户端,但在YSleepHandler的情况下,当处理程序运行时,其他请求可以被处理,因为IOLoop是没有阻止。