FastAPI - Hitting the Performance Jackpot. Part 1 - Asynchronicity
Nowadays, most new microservices written in Python use FastAPI. The name suggests it's fast, but have you dug into understanding why? In this blog post, I'll explain why FastAPI is so performant and so widely chosen as a go-to framework for Python services. Moreover, I had the opportunity to discuss this topic in my talk at PyCon Italy, where the room was full—showing just how much interest there is in this subject.
FastAPI's performance stands on three pillars. Throughout this blog post, you'll discover the first of them.
Asynchronicity
Asynchronous programming is crucial for performance in web applications as it's the optimal solution for handling multiple tasks - which is the case in web applications as those are written to handle multiple concurrent requests. For those who are new to asynchronous programming, check out my blog post Demystifying Asynchronous Programming in Python. Reading it first will help you understand how it works.
First and foremost, FastAPI requires a web server capable of serving the application asynchronously. While WSGI is a well-known and production-ready solution for web apps, it handles them as single, synchronous callables that take a request and return a response. This setup doesn't support long-lived connections, such as those needed for long-poll HTTP or WebSockets.
This is where ASGI (Asynchronous Server Gateway Interface) comes into play. ASGI is asynchronous and defines the communication between the web application and the web server. As the successor to WSGI, it maintains compatibility with it while offering the benefits of asynchronous handling.
Architecture:
A typical architecture for a FastAPI application involves several key components working together seamlessly. The process starts when a client sends a request, which is handled by a web server, commonly NGINX. NGINX serves multiple roles: it delivers static files, protects against DDoS attacks, load balances incoming traffic, and acts as a reverse proxy to the WSGI server. In this setup, a WSGI server like Gunicorn runs multiple ASGI server workers, such as Uvicorn with uvloop. Gunicorn functions as a process manager, listening on the port and IP, then transmitting the communication to Uvicorn. Uvicorn converts the data to the ASGI standard, which FastAPI relies on to utilize the full benefits of asynchronous programming.
One of the key components in this setup is Uvicorn which is an ASGI web server implementation for Python. It supports HTTP/1.1 and WebSockets, and relies on the uvloop as the event loop.
uvloop is a drop-in replacement of the asyncio event loop. It speeds up asyncio a lot as it's written in Cython on top of libuv which is high performance, multiplatform asynchronous I/O library used by nodejs. Based on these benchmarks it shows that uvloop makes asyncio from 2 to 4 times faster.
These components are known for their strong performance, making them the perfect fundament for reliable and fast web frameworks. This is how FastAPI achieves the performance. But at that point, it's kind of low-level and it'd require a lot of effort to have all common web-related features in the framework. That's why one additional building block is needed for FastAPI.
Starlette
Starlette, a lightweight ASGI framework, is the unsung hero of Python's async web services. This framework, designed for building high-performance, asynchronous web applications, provides a robust set of features that simplify the development process. With its low-complexity HTTP web framework, WebSocket support, and in-process background tasks, Starlette offers a solid foundation for developers to build scalable and efficient applications.
Moreover, its 100% test coverage and type-annotated codebase ensure reliability and maintainability. By adding an abstraction layer over uvicorn, Starlette allows developers to focus on writing clean, efficient code without worrying about the underlying complexities of async programming.
FastAPI & Starlette
You might be familiar with this style of code, as it's very similar to FastAPI. In fact, the relation is reversed - FastAPI code is similar to Starlette. That's because
"FastAPI is just a Starlette on steroids" [1]
FastAPI directly uses all features from Starlette such as background tasks, the test client, web sockets, middleware, path converter, and many more. And introduces handy decorators, and other features that makes the code more concise and easy to write. FastAPI also made some decisions about data validation but this will be covered in the next blog post.
Benchmarks
When comparing Starlette to other popular Python frameworks like tornado, Django, and Flask, it becomes evident that Starlette is significantly faster. In fact, Starlette is approximately twice as fast as tornado, and nearly ten times faster than Flask or Django. Obviously, Starlette also outperforms FastAPI in terms of speed as FastAPI derives from it.
Summary
FastAPI is indeed fast. Because it's asynchronous which is the optimal way in web development and because of the performant fundaments such as uvicorn and uvloop.
- Asynchronous programming: FastAPI uses ASGI, which supports asynchronous programming, allowing it to handle multiple requests simultaneously.
- Starlette framework: FastAPI is built on top of Starlette, which provides a lightweight, low-complexity HTTP web framework.
- Uvicorn server: FastAPI applications run under Uvicorn, a high-performance ASGI server that uses uvloop to boost performance to the limits by replacing asyncio.
In the next blog post, I'll cover how FastAPI handles the data, and why it's critical for the performance.
References:
[1] - https://fastapi.tiangolo.com/features/#starlette-features
Member discussion