Reputation: 1256
So I understand the basic idea that Tornado is itself non blocking with an event loop I/O, but that blocking IO operations like database access will result in Tornado blocking during those operations.
What I don't understand is why it seems that Tornado is blocking during non-blocking operations.
I have the following code in a handler:
class MyHandler(BaseHandler):
def get(self):
x = 0
for i in xrange(0,500000000):
x = i
self.render("page_temp.html",
title="Page"
)
This takes ~20 seconds to load the page. If I open another browser window and try to load any other page, I get hung until the 20 second page loads. Could it be because both requests are from the same user?
Upvotes: 2
Views: 925
Reputation: 94881
You're doing a long, CPU-bound operation directly inside your handler. tornado
is single-threaded, which means it can't do CPU-bound work in the event loop thread without blocking all your other requests. If you need to do CPU-bound work, you have to do it in a background thread or process.
In order to make this method handle requests concurrently, it would need to look like this:
from concurrent.futures import ThreadPoolExecutor
from tornado import gen
from tornado.web import RequestHandler
executor = ThreadPoolExecutor(8) # 8 Threads in the pool
class ThreadPoolHandler(RequestHandler):
def _do_loop(self):
x = 0
for i in xrange(0,500000000):
x = i
@gen.coroutine
def get(self):
yield executor.submit(self._do_loop) # Run through the loop without blocking tornado
self.render("page_temp.html",
title="Page"
)
By using a ThreadPoolExecutor
to run the expensive for-loop in a background thread, tornado
can continue to serve other requests while waiting for the CPU work to complete.
Upvotes: 4