Siddhant Goel


Not everything needs to be async

May 25, 2019 · #programming #python

Writing asynchronous code is popular these days. Look at this search trend from the last 5 years.

Async Python

I have the feeling that the number of tutorials on the internet explaining asynchronous code has increased quite a bit since Python started supporting the async/await keywords. Even though Python has always had support for running asynchronous code using the asyncore module (or using libraries like Twisted), I don't think that asyncore was used as much as the new asyncio. This is a pure gut feeling though; I have no numbers to back that claim up.

Anyway, asyncio makes it slightly easier to write asynchronous code. Slightly, because I don't know if I can call the API as intuitive, or dare I say, "Pythonic". This article does a much better job of explaining why asyncio is what it is.

Even if we put asyncio aside, I don't think asynchronous code is ever easy. There's just so much going on under the hood that it's difficult to keep your head from spinning, before you can actually get to writing the application logic.

But that's not what this blog post is about. This blog post is about how not everything needs to be async. And that if some code you're working on absolutely necessarily must be async, then why it makes sense to stop for a minute and consider the consequences of introducing this extra level of complexity.

This has nothing to do with Python, or asyncio, or any async framework in general. All I want to say, is, if you think you want to write asynchronous code, think twice.

Synchronous is much simpler

Synchronous code is simple to write. It's also much easier to reason about, and it's lot less likely to contain concurrency or thread-safety bugs than asynchronous code. As programmers, our job is to solve business problems reliably in the least possible time. Synchronous code fits that criteria quite well. So if I'm given a choice between writing synchronous or asynchronous, I can say with a reasonable amount of confidence that I'll prefer synchronous.

Would async really help?

Next, if asynchronous code is absolutely required, it makes sense to think about what it's going to do underneath, and what performance gains it's going to bring.

For instance, if you're writing a web request handler which calls out a few external APIs and combines those responses to finally return a response to your user, yes, asynchronous code would absolutely help. The time that the external resources make your request handler wait can be used to serve other user requests.

On the other hand, if your request handler is fetching a few rows from a database server that's running on the same machine as the app server, it's not going to make that much of a difference if it were async.

Is it safe?

Often times we end up using abstractions that hide away the implementation details and provide a nice API for us to work with. In these cases, it's important to know what exactly is being hidden, or how that abstraction is working underneath.

For example, Python provides an abstraction called ThreadPoolExecutor, which allows you to run functions in separate threads (there is also ProcessPoolExecutor which lets you separate things on a process-level).

The way this works is that you submit a callable to the pool, and the pool returns a Future object immediately. And when the function has finished running, the results (or the exception) would be stored in this future object.

Since there are Future objects involved (which you can await on), it can be tempting to use this abstraction to write async code. But because now there are multiple threads involved, it's not that simple anymore. The functions being submitted to the thread pool should now only make use of resources that are thread-safe. In case two callables are submitted to the pool, both referencing a particular object which is not thread-safe, there's potential for weird concurrency bugs.


Closing thoughts - async is useful (and cool), but there is a time and place for everything. It may result in an increased CPU utilization without necessarily bringing speed improvements, so it's helpful to keep that in mind when writing async code.