为什么龙卷风异步不起作用
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()});
}
今天,当我想使一些同步 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()});
}