The Django Speed Handbook: making a Django app faster by Shibel K. Mansour ( https://twitter.com/SHxKM ) ¶
In Dec 2019, we saw the release of Django 3.0 with an interesting new feature — support for ASGI servers.
I was intrigued by what this meant. When I checked the performance benchmarks of asynchronous Python web frameworks they were ridiculously faster than their synchronous counterparts often by a factor of 3x–5x.
So I set out to test Django 3.0 performance with a very simple Docker setup. The results — though not spectacular — were still impressive.
But before that, you might need a little bit of background about ASGI.
So if we were perfectly fine with WSGI, why did we have to come up with ASGI ? The answer will be quite evident if you have followed the path of a webrequest. Check out my animation of how a webrequest flows into Django .
Notice how the framework is waiting after querying the database before sending the response. This is the drawback of synchronous processing .
Frankly this drawback was not obvious or pressing until Node.js came into the scene in 2009. Ryan Dahl, the creator of Node.js, was bothered by the C10K problem i.e. why popular web servers like Apache cannot handle 10,000 or more concurrent connections (given a typical web server hardware it would run out of memory).
He asked “What is the software doing while it queries the database ?”.
The answer was, of course, nothing. It was waiting for the database to respond. Ryan argued that webservers should not be waiting on I/O activities at all.
Instead it should switch to serving other requests and get notified when the slow activity is completed. Using this technique, Node.js could serve many orders of magnitude more users using less memory and on a single thread!
It was becoming increasingly clear that asynchronous event-based architectures are the right way to solve many kinds of concurrency problems. Probably that is why Python’s creator Guido himself worked towards a language level support with the Tulip project, which later became the asyncio module.
Eventually Python 3.7 added the new keywords async and await to support asynchronous event loops. This has pretty significant consequences in not just how Python code is written but executed as well.
This also brings us to the crux of the problem with bringing all the async goodness to Django - all of Django was written in synchronous style code.
If we need to write any asynchronous code then there needs to be a clone of the entire Django framework written in asynchronous style.
In other words, create two worlds of Django.
Well, don’t panic — we might not have to write an entire clone as there are clever ways to reuse bits of code between the two worlds.
But as Andrew Godwin who leads Django’s Async Project rightly remarks “it’s one of the biggest overhauls of Django in its history”.
An ambitious project involving reimplementation of components like ORM, request handler, Template renderer etc in asynchronous style.
This will be done in phases and in several releases. Here is how Andrew envisions it (not to be taken as a committed schedule):
Django 3.0 - ASGI Server
Django 3.1 - Async Views (see an example below )
Django 3.2/4.0 - Async ORM
You might be thinking what about the rest of the components like Template rendering, Forms, Cache etc.
They may still remain synchronous or an asynchronous implementation be fitted somewhere in the future roadmap.
But the above are the key milestones in evolving Django to work in an asynchronous world.