The web is a big place now. We need to support thousands of clients at a time, and here comes Tornado. 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.
Tornado is not like most Python frameworks. It's not based on WSGI, while it supports some features of WSGI using module `tornado.wsgi`. It uses an event loop design that makes Tornado request execution faster.
What is Synchronous Program?
A function blocks, performs its computation, and returns, once done . A function may block for many reasons: network I/O, disk I/O, mutexes, etc.
Application performance depends on how efficiently application uses CPU cycles, that's why blocking statements/calls must be taken seriously. Consider password hashing functions like bcrypt, which by design use hundreds of milliseconds of CPU time, far more than a typical network or disk access. As the CPU is not idle, there is no need to go for asynchronous functions.
A function can be blocking in one, and non-blocking in others. In the context of Tornado, we generally consider blocking due to network I/O and disk, although all kinds of blocking need to be minimized.
What is Asynchronous Program?
1) Single-threaded architecture:
Means, it can't do computation-centric tasks parallely.
2) I/O concurrency:
It can handover IO tasks to the operating system and continue to the next task to achieve parallelism.
3) epoll/ kqueue:
Underline system-related construct that allows an application to get events on a file descriptor or I/O specific tasks.
4) Event loop:
It uses epoll or kqueue to check if any event has happened, and executes callback that is waiting for those network events.
Asynchronous vs Synchronous Web Framework:
In case of synchronous model, each request or task is transferred to thread or routing, and as it finishes, the result is handed over to the caller. Here, managing things are easy, but creating new threads is too much overhead.
On the other hand, in Asynchronous framework, like Node.js, there is a single-threaded model, so very less overhead, but it has complexity.
Let's imagine thousands of requests coming through and a server uses event loop and callback. Now, until request gets processed, it has to efficiently store and manage the state of that request to map callback result to the actual client.
Node.js vs Tornado
Most of these comparison points are tied to actual programming language and not the framework:
- Node.js has one big advantage that all of its libraries are Async. In Python, there are lots of available packages, but very few of them are asynchronous
- As Node.js is JavaScript runtime, and we can use JS for both front and back-end, developers can keep only one codebase and share the same utility library
- Google’s V8 engine makes Node.js faster than Tornado. But a lot of Python libraries are written in C and can be faster alternatives.
A Simple 'Hello World' Example
CODE: https://gist.github.com/velotiotech/b4d91554b739f2487bf6131ac65ec06d.js
Note: This example does not use any asynchronous feature.
Using AsyncHTTPClient module, we can do REST call asynchronously.
CODE: https://gist.github.com/velotiotech/5fe63eb5fd6cf3af9bf353c2fd3b4ca7.js
As you can see `yield http_client.fetch(url)` will run as a coroutine.
Complex Example of Tornado Async
Please have a look at Asynchronous Request handler.
WebSockets Using Tornado:
Tornado has built-in package for WebSockets that can be easily used with coroutines to achieve concurrency, here is one example:
CODE: https://gist.github.com/velotiotech/34d0a0e0ecd57818ae1db1697c075777.js
One can use a WebSocket client application to connect to the server, message can be any integer. After processing, the client receives the result if the integer is prime or not.
Here is one more example of actual async features of Tornado. Many will find it similar to Golang’s Goroutine and channels.
In this example, we can start worker(s) and they will listen to the 'tornado.queue'. This queue is asynchronous and very similar to the asyncio package.
CODE: https://gist.github.com/velotiotech/1477131948ca23879167df0281726d02.js
Conclusion
1) Asynchronous frameworks are not much of use when most of the computations are CPU centric and not I/O.
2) Due to a single thread per core model and event loop, it can manage thousands of active client connections.
3) Many say Django is too big, Flask is too small, and Tornado is just right:)