Asyncio — Moving towards the asynchronous future of Python

Kyle Hanson
May 20, 2020 · 5 min read
Image for post
Image for post

A split bigger than the decade long transition from 2 to 3 is well underway in the Python community. Coroutines and async/await syntax have existed in Python since version 3.5 released in 2015, but tools and projects utilizing the feature were slow to be released. Mature libraries to build async applications are starting to become available and the libraries we love are moving in the async direction. Async is the future of Python.

Why it matters

Asyncio is the biggest change since the language’s introduction. It is a library and additional syntax that programmers use to mark their python code. The syntax tells what functions are making IO calls allowing the interpreter to schedule concurrent tasks on a single thread. Without asyncio, when python code waits for network responses, like from a database, it blocks the whole thread.

Anything that introduces latency and blocks the thread needs to be labeled as a coroutine. Database connectors, caches, ORMs, web frameworks and a lot more all need to be rewritten. The fastest web frameworks in Python use asyncio. However, their adoption has been slowed because the lack of companion libraries.

What it is replacing

Concurrency in Python used to be invisible. It is primarily needed for web frameworks, and we have a great generalized tool to run those: gunicorn. Gunicorn is an HTTP server which runs an WSGI application, a specification which Django and Flask use. It could achieve concurrency by utilizing gevent. Gevent patches all network calls to avoid blocking the thread in much of the same way asyncio does. Gevent patches the calls automatically, making ORMs, caches and everything else work with zero work required. It is monkey-patching the language instead of letting the interpreter handle concurrency natively. This was said in a Django developer document about gevent:

While the idea of having methods and functions seems attractive at first, there are many subtle problems with the greenlet-based approach. The lack of an explicit or means that a complex API like Django's basically becomes unpredictable as to knowing if it will block the current execution context or not. This then leads to a much higher risk of race conditions and deadlocks without careful programming, something I have experienced first-hand.

The State of Asyncio

Asyncio is most useful in web frameworks and we are starting to see many mature ones arrive. Databases and ORMs are more complicated and so are seeing slower development.


One of Python’s most popular web framework, Django, is not based on asyncio. The latest 3.0 release added support for ASGI, the async counterpart to WSGI. With ASGI you can use daphne or uvicorn to run your application. More async support is planned for 3.1 with asynchronous views and middleware. These are the first steps to supporting asyncio. A fully asynchronous Django would need a complete rewrite of the ORM, cache interface, templates and email. There exists a very big list of everything that needs to be done. Django will be the big push for many into the async world.


The most promising framework based on asyncio is FastAPI. While it is more focused on filling Flask’s old place then it is replacing Django, it is an entirely revolutionary way to create APIs in Python. It makes producing JSON APIs which parse and validate incoming data as simple as using type annotations. In fact the entire framework is based on type annotations, even when you want to specify what resources your view will use. Its also benchmarked as the fastest framework, no doubt thanks to asyncio! FastAPI also allows you to write synchronous views for when you need to fall back to an adapter that hasn’t gone async yet.


Interacting with the database is the one big weakness of async libraries. While the low level adapters, Redis, PostgreSQL, MySQL, etc. have been written, the ORM libraries need work. SqlAlchemy works in some limited capacity thanks to the databases project. However, it still doesn’t give you 100% of the ORM capabilities of SqlAlchemy as statements are returned as record objects instead of models. There exists Sqlalchemy_aio, but that isn’t a true asyncio library (more on that below). A young project named tortoise-orm looks promising, but lacks the advanced query building capabilities of SqlAlchemy or Django. A true asyncio version of SqlAlchemy is needed.


The biggest impediment to adoption are libraries. The async forks of libraries are less maintained then the synchronous counterparts, if they exist at all. Python has been a great language to rely on for obscure tools. Now, it might be a bit complex to use that adapter in the latest web framework. Sometimes async versions of libraries get around the problems by running sync operations in a separate thread. This doesn’t give the best performance. Sqlalchemy_aio has this to say:

It’s not an asyncio implementation of SQLAlchemy or the drivers it uses. sqlalchemy_aio lets you use SQLAlchemy by running operations in a separate thread. […] If performance is critical, perhaps asyncpg can help.

The second biggest hurdle to adoption is that the current solution, gevent, just works. Once you introduce a database query, the latency from the query outweigh the optimizations that asyncio has over gevent. Rewriting all code for such a small benefit isn’t on the top of a lot of peoples mind.

An Async-First Future

Today when building a new python library, developers need to make a choice to use asyncio. In the past, the low adoption meant this wasn’t on a lot of people’s radars. But libraries that consume APIs or use database connections should be written in an async safe way. Attempting to run synchronous code in an asynchronous context is difficult, but the opposite is not. To be future proof, we need to be writing libraries to use asyncio and view current synchronous solutions as deprecated.

To prepare yourself for the Async future, when writing APIs use httpx in asynchronous mode. When you write a library that can use async, use async. If you have to use it from a synchronous context use . Django recommends using to execute async code as another option.

It may take another decade for this next phase of Python to finally be broadly adopted, but mature libraries that top the performance charts show that its doing something right. The future of Python is async and it is fast!

Analytics Vidhya

Analytics Vidhya is a community of Analytics and Data…

Sign up for Analytics Vidhya News Bytes

By Analytics Vidhya

Latest news from Analytics Vidhya on our Hackathons and some of our best articles! Take a look

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Kyle Hanson

Written by

Programmer, Functional programming aficionado

Analytics Vidhya

Analytics Vidhya is a community of Analytics and Data Science professionals. We are building the next-gen data science ecosystem

Kyle Hanson

Written by

Programmer, Functional programming aficionado

Analytics Vidhya

Analytics Vidhya is a community of Analytics and Data Science professionals. We are building the next-gen data science ecosystem

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store