Asynchrony in Django: Craze or Necessity?
Asynchrony in Django is a rather controversial topic.
It seems Django developers decided to tune into the asynchrony theme by adding support for asynchronous views to Django, starting with version 3.1.
Typically, developers are highly cautious about extending Django's core functionality unless there's an urgent need. The emergence of asynchrony only goes to highlight how fundamentally critical asynchronous features are. But not all tasks lend themselves to such solutions.
Why Python needs asynchrony
Asynchrony was the response to slow external communication, relatively slow network connectivity, disks, and other infrastructure. Its basic idea is that many operations can be performed asynchronously. In this way, CPU time is more efficiently allocated: while some tasks are waiting for I/O operations to complete, the CPU is working on computation where it is currently needed. Asynchrony is an alternative paradigm to multithreading or process forking.
Properly built asynchronous applications can process thousands of network connections. But the asynchronous mode is suitable only in some areas, for example, in tasks requiring CPU time for computation, such as video encoding or intensive arithmetic operations. Python has adopted asynchrony since version 3.5 in the form of async/await statements. Before version 3.5, generator-based approaches such as Twisted were used.
The asynchronous mode existed before that and is well known. For C++, it is implemented in the well-established ACE framework.
Issues with asynchrony in Django
Django decided to adopt and heavily promote asynchrony. However, one of Django's slowest end-user operations is working with the database. It's still synchronous. The developers just added a wrapper that puts synchronous database calls into threads. So they "pretend" to be asynchronous.
The bridge between the synchronous database and asynchronous operations is implemented through wrapping with sync_to_async. This wrapping implements a connection to the database in a separate thread and waits for data to be received. Then, in asynchronous style, it passes on the query results as an asynchronous iterator.
Many people criticize Django developers for their efforts to create asynchrony. Suppose the architect decides that the application architecture needs an asynchronous system. In that case, he should choose other frameworks from the beginning and lay down mechanisms that assume there will be asynchrony, an efficient bus on technologies like AMQP or Kafka, for example. Django and asynchrony are still controversial choices when designing applications.
With the advent of asynchronous support in Python, which previously existed as separate technologies (e.g., Twisted), the trend toward asynchronous frameworks has begun.
Python-based asynchronous frameworks
The asynchronous library in Python has been implemented by the asyncio module since version 3.4 and is part of the set of standard libraries. The library includes all the basic tasks needed to develop asynchronous applications.
This library allows developers to build highly efficient microservices and get the most out of the CPU core. Generally, such microservices withstand a high load and a large number of simultaneous connections precisely due to their asynchronous nature. A request is received and sent to a slow external resource, such as a bus or a database, and while the external resource is processing this request, other processes are executed.
For example, asynchronous Python frameworks exist today that cover various scenarios with parallel high-workloads and heavily parallelizable queries:
Before you enable asynchrony in Django, find out if this is really the asynchrony you need. If you expect to process many requests, explore other suitable frameworks.