Why Asynchronous Tornado Doesn't Work

Today when I want some synchronous Python library to function asynchronously, but it doesn't work. After a series of tests, I found that it even yield tornado.gen.sleep(N)

works synchronously.

Here's my code:

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()

      

I use the following code to check if the asynchronous function is working or not (in the file test.htm - the template file for the MainHandler):

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

      

But finally I got an unexpected result .

What happened? I have tried in both Python2.7 and Python3.4 environments.

+3


source to share


2 answers


Finally, this problem was solved by adding some unique useless arguments to the end of the url.

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

      



If you use the above code to check the result, you will get the same result as using synchronous code (since tornado will return 304 unchanged, this is a synchronous function.). but if you use the code below, the differences between synchronous and asynchronous will be fully illustrated.

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


source


You see this behavior because the exit in the coroutine effectively transfers control to Tornado IOLoop. This does not mean that it returns the result to the client - it just returns control to Tornado so that IOLoop does not get blocked by a long request.



The effect this has on your code is that Tornado will block while SleepHandler is running, whereas it will not block when YSleepHandler is run. In both cases, a response will only be returned to the client when your handler calls self.write (), but in the case of YSleepHandler, other requests can be handled while the handler is running because the IOLoop is not blocked.

0


source







All Articles