Tornado is an asynchronous networking library and web framework originally developed by FriendFeed. By utilizing non-blocking network I/O, it efficiently handles thousands of simultaneous connections, making it an ideal choice for persistent connections, WebSockets, and high-concurrency environments.
Key Mechanisms for High Performance
- Asynchronous Non-blocking I/O: The system does not pause while waiting for I/O operations to complete.
- Event Loop via epoll: It monitors multiple file descriptors simultaneously to determine which are ready for I/O.
- Coroutine Support: Simplifies asynchronous logic, improving readability and maintainability compared to traditional callback chains.
Important: Never execute synchronous, blocking code within a Tornado application. Becuase the framework runs on a single-threaded event loop, any blocking operation will halt all other concurrent tasks.
Core Components
- Web Framework: Tools like
RequestHandlerfor building web applications. - HTTP Implementation:
HTTPServerandAsyncHTTPClientclasses. - Networking Layer:
IOLoopandIOStreamwhich act as the foundation for I/O handling. - Coroutines: The
tornado.genmodule andasync/awaitsyntax for writing asynchronous code that reads like synchronous code.
Non-blocking Networking Example
To manage asynchronous operations efficiently, one can leverage the selectors module to implement a custom event loop:
import socket
from selectors import DefaultSelector, EVENT_WRITE, EVENT_READ
selector = DefaultSelector()
class AsyncConnector:
def __init__(self, target):
self.target = target
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setblocking(False)
self.payload = b""
def on_ready(self, key):
self.sock.send(f"GET / HTTP/1.1\r\nHost:{self.target}\r\nConnection:close\r\n\r\n".encode())
selector.unregister(key.fd)
selector.register(self.sock.fileno(), EVENT_READ, self.handle_read)
def handle_read(self, key):
chunk = self.sock.recv(4096)
if chunk:
self.payload += chunk
else:
selector.unregister(key.fd)
print(self.payload.decode())
def execute(self):
try:
self.sock.connect((self.target, 80))
except BlockingIOError:
pass
selector.register(self.sock.fileno(), EVENT_WRITE, self.on_ready)
conn = AsyncConnector("www.example.com")
conn.execute()
while True:
for key, _ in selector.select():
callback = key.data
callback(key)
Asynchronous HTTP Requests
Tornado simplifies network requests via AsyncHTTPClient, allowing developers to integrate external API calls into their asynchronous flow seamlessly:
from tornado import httpclient, ioloop
async def fetch_content(url):
client = httpclient.AsyncHTTPClient()
response = await client.fetch(url)
return response.body
if __name__ == "__main__":
content = ioloop.IOLoop.current().run_sync(lambda: fetch_content("https://www.google.com"))
print(f"Fetched {len(content)} bytes")
By leveraging these non-blocking primitives, Tornado applications maintain high throughput without the overhead associated with traditional thread-per-request models.