Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Tornado - Asynchronous Request is blocking

The request handlers are as follows:

class TestHandler(tornado.web.RequestHandler):    #  localhost:8888/test
    @tornado.web.asynchronous
    def get(self):
        t = threading.Thread(target = self.newThread)
        t.start()

    def newThread(self):
        print "new thread called, sleeping"
        time.sleep(10)
        self.write("Awake after 10 seconds!")
        self.finish()

class IndexHandler(tornado.web.RequestHandler):           #   localhost:8888/ 
    def get(self):
        self.write("It is not blocked!")
        self.finish()

When I GET localhost:8888/test, the page loads 10 seconds and shows Awake after 10 seconds; while it is loading, if I open localhost:8888/index in a new browser tab, the new index page is not blocked and loaded instantly. These fit my expectation.

However, while the /test is loading, if I open another /test in a new browser tab, it is blocked. The second /test only starts processing after the first has finished.

What mistakes have I made here?

like image 582
MK Yung Avatar asked Jun 08 '14 13:06

MK Yung


People also ask

Is asynchronous and non-blocking same?

Non-Blocking: It refers to the program that does not block the execution of further operations. Non-Blocking methods are executed asynchronously. Asynchronously means that the program may not necessarily execute line by line.

Is Tornado asynchronous?

Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed.

Is Tornado single threaded?

The reason is that Tornado is an asynchronous server with only one thread.

How does Tornado work in Python?

Tornado is a Python web framework and asynchronous network library, originally developed at FriendFreed. Tornado uses non-blocking network-io. Due to this, it can handle thousands of active server connections. It is a saviour for applications where long polling and a large number of active connections are maintained.


1 Answers

What you are seeing is actually a browser limitation, not an issue with your code. I added some extra logging to your TestHandler to make this clear:

class TestHandler(tornado.web.RequestHandler):    #  localhost:8888/test
    @tornado.web.asynchronous
    def get(self):
        print "Thread starting %s" % time.time()
        t = threading.Thread(target = self.newThread)
        t.start()

    def newThread(self):
        print "new thread called, sleeping %s" % time.time()
        time.sleep(10)
        self.write("Awake after 10 seconds!" % time.time())
        self.finish()

If I open two curl sessions to localhost/test simultaneously, I get this on the server side:

Thread starting 1402236952.17
new thread called, sleeping 1402236952.17
Thread starting 1402236953.21
new thread called, sleeping 1402236953.21

And this on the client side:

Awake after 10 seconds! 1402236962.18
Awake after 10 seconds! 1402236963.22

Which is exactly what you expect. However in Chromium, I get the same behavior as you. I think that Chromium (perhaps all browsers) will only allow one connection at a time to be opened to the same URL. I confirmed this by making IndexHandler run the same code as TestHandler, except with slightly different log messages. Here's the output when opening two browser windows, one to /test, and one to /index:

index Thread starting 1402237590.03
index new thread called, sleeping 1402237590.03
Thread starting 1402237592.19
new thread called, sleeping 1402237592.19

As you can see both ran concurrently without issue.

like image 104
dano Avatar answered Sep 25 '22 02:09

dano