How asynchronous applications work in Python
Tags: python, asynchronous, programming
Published: 2023-09-01 01:30:02

Python is a synchronous language, which means that requests will have to wait for another request to process. That is to say, one function call waits for another to complete, and the program pauses until a specific task is done.

The concept of asynchronous programming is confusing to beginners because of its complexity, non-sequential approach, and the learning curve it presents. In this article, I will explain asynchronous programming, how it works, and how to implement it in Python.

## Prerequisites
Although this is an entry-level topic, I will assume that you are familiar with or have done the following:

- Basic programming knowledge
- A code editor
- Python installed
- Willingness to learn

## What is asynchronous programming?

Have you ever handled tasks that require a significant amount of time to complete, like sending multiple emails or downloading and uploading videos? Users often find it frustrating to wait through these processes. This is where “asynchronous” comes into action.

Asynchronous programming in Python is a technique that enables you to write code that can perform multiple tasks concurrently without blocking the execution of other tasks.

Asynchronous means never waiting but keep executing. So if a task gets interrupted, it takes up the next task and executes it. So, in this scenario, your code does not block, instead the requests and function calls are executed in the background and inform you at a later time once the process is completed.

### Asynchronous vs Synchronous

The table below highlights the differences between synchronous and asynchronous programming.


![A table highlighting the difference between synchronous and asynchronous](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/im1jidy4ey6tojk27ese.png)

### How asynchronous applications work

Let’s take WhatsApp as an example. Imagine you post a status update, but while it's still getting ready to go up, you send a message to a friend. Your message gets sent immediately. Then, your mom calls you. While you are in a conversation, you begin downloading a video shared by a friend. Later, when you check again, you notice that your status is finally up. During this time, you are also sending a picture to your mom, all while still on the call.


![An image to visualize synchronous and asynchronous](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ocfjs5617qw8sbt9iq3o.png)

In reality, the app is multitasking by assigning a separate thread to handle each task or sequence of instructions. We will delve into the concept of a “**thread**” in a later article. So, what is happening is that the application is performing context switching. For instance, if the file you were uploading for your status was taking a while due to the network or its large size, the app doesn’t keep you waiting. Instead, it moves onto the next task in line and handles it concurrently. 

If this were a “synchronous approach”, you would be left waiting for the status to finish uploading, freezing up everything and preventing other actions. This is where “asynchronous” programming steps in as a solution. Its essence is simple: “Don't keep me waiting, just keep things moving while I provide further instruction.”

Here is a simple code snippet to illustrate what is happening in the background. As you can see, this function is synchronous. It needs to wait for the video upload to complete before showing a success message. If we were to make this asynchronous, a success message would be displayed right away, while the encoding takes place in the background.

```
def upload_video():
    print('encoding')
   
def upload_status():
    print('uploading...')
    upload = upload_video()
    print(f’Your status is ready {upload}')
```

There are different ways to achieve asynchronous programming in Python, but this is beyond the scope of this article.

### Benefits of asynchronous programming

- It allows you to perform non-blocking I/O operations. This prevents the application from becoming unresponsive and allows it to continue executing other tasks while waiting for I/O operations to finish.
- It is essential for building real-time applications like chat systems, online gaming, and financial trading platforms, where quick response times are vital.

### Task

It's time to put into practice what you have learned.

1. Open your code editor. 
2. Write a function that prints out numbers 1-30 sequentially. NOTE: You can use a while or for loop.
3. Modify the function to note down the starting and ending times. 
4. Using the results from above. Calculate the elapsed time and record it. We will be needing the result later.
5. Experiment with the `sleep()` function. Make numbers 8 and 12 “sleep” for a certain number of seconds. 

What do you notice? Let's say 8 was to “sleep” for 8 seconds. The program doesn't display 9 until 8 is done “sleeping” and prints out a result.

You can try printing 'start sleeping' just before `sleep()`, and after that, print 'done sleeping'.

Are you taking note of what is happening?

In a real-world scenario, your users would have to wait for 8 seconds. Sounds frustrating, doesn’t it? There could be a better way, right?

That is all for now. We will explore how to make it work asynchronously in the next article.

### Conclusion

We have learned that Python typically executes function calls one after another in sequence—which  results in upcoming tasks being on hold until the previous one concludes its execution.
We have discussed what asynchronous programming is, the mode of operation and the problems it solves. You have run a synchronous function and identified its setbacks.
Now that you have an introductory understanding of asynchronous programming, take a look at this [next article](https://dev.to/praise002/how-to-build-asynchronous-applications-in-python-exploring-multithreading-3cof) which offers a deep dive into asynchronous programming.