Tornado is one of the most popular web framework for Python, which is based on a single thread IO loop (aka event loop). You can handle high concurrency with optimal performance. However, Tornado is single threaded (in its common usage, although in supports multiple threads in advanced configurations), therefore any "blocking" task will block the whole server. This means that a blocking task will not allow the framework to pick the next task waiting to be processed.
For example, this is a wrong way of using IOLoop
:
Note that get_complex_result()
is called correctly, but it is blocked by time.sleep(5)
, which will prevent the execution of the following tasks (such as a second request to the same function). Only when the first request is finished, the second request will be handled by IOLoop.
The solution to the blocking problem is to use asynchronous
or coroutine
annotation.
In the above code, the Tornado application can handle requests in MainHandler
and ComplexHandler
simultaneously. However, in some situations, some packages do not support asynchronous and will still block requests. ThreadPoolExecutor
are incorporated to tackle this problem.
In Python 2, you need to install a package called futures
.
ThreadPoolExecutor
is a high level encapsulation of threading in the standard library, making functions run asynchronously with the help of threads.
References
- https://hexiangyu.me/posts/15
- https://gist.github.com/lbolla/3826189
- https://www.peterbe.com/plog/worrying-about-io-blocking
- http://www.tornadoweb.org/en/stable/concurrent.html
- http://www.tornadoweb.org/en/stable/guide/coroutines.html