AsyncIO basics in Python
Tags: python, programming
Published: 2023-07-09 16:15:23

While there are methods that facilitate parallel programming in Python, it is a single-threaded language by default. To avail the full advantage of single-threaded execution, we can make use of the AsyncIO library. 

## Asynchronous code
As its name suggests, AsyncIO provides asynchronous execution in Python. Asynchronous code runs in a non-blocking way. If a function has a longer wait time, another task can be performed during the waiting period, instead of all the tasks being put on hold.

The following image further explains synchronous vs asynchronous code execution. While waiting for the first response, we can make the second request to better utilize the processing capabilities. 

![Asynchronous vs synchronous code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twcagkddmee8yzjc5w2p.png)

 
Although it does not make use of multi-threading, it does perform concurrent execution of code and reduces wait time considerably in many cases. 

##Using AsyncIO

AsyncIO library has two major keywords:
**1. async**
**2. await**
We can use the keywords **async def** to define a coroutine. 
The **await** keyword is used inside an async coroutine to suggest that the program should wait here and execute something else in the meantime. 

Take a look at the code below.

```python
import asyncio

async def co_routine(num):
    print('Entered coroutine number : ', num)
    await asyncio.sleep(2)
    print('Exiting coroutine number : ', num)
    
async def main():
    await asyncio.gather(co_routine(1), 
                         co_routine(2), 
                         co_routine(3))
        
        
asyncio.run(main())
```

Here's the output!

```
Entered coroutine number :  1
Entered coroutine number :  2
Entered coroutine number :  3
Exiting coroutine number :  1
Exiting coroutine number :  2
Exiting coroutine number :  3
```

As you can see, we did not have to wait for coroutine 1 to finish executing before moving on to coroutines 2 and 3. Let's see the code step by step. 

```python
import asyncio
```
This imports the asyncio library to your python code. 

```python
async def co_routine(num):
    print('Entered coroutine number : ', num)
    await asyncio.sleep(2)
    print('Exiting coroutine number : ', num)
```
This is our asynchronous coroutine. We define it using the **async def** keywords. We print a message on entering and then the coroutine sleeps for 2 seconds. This is where the magic happens. The **await** keywords signals that we have to wait, so the program can execute something else. 
**An await keyword can only be used inside an async coroutine!**

```python
async def main():
    await asyncio.gather(co_routine(1), 
                         co_routine(2), 
                         co_routine(3))
```
This defines our asynchronous main. **asyncio.gather** takes multiple coroutine calls and waits for them to execute concurrently before returning. Here, we run our coroutine for values 1, 2, and 3. Since we had to use the await keywords, our main is also defined as async. 

However, for our final call, we can use **asyncio.run**. 

```python
asyncio.run(main())
```
This executes our main without the need to use await. 

Now, you can use async/await in the programs you wish to run concurrently.