Introduction to Using Async/Await in Python
Tags: python, asyncio, multitasking, coroutines
Published: 2020-04-26 23:59:11

You probably might have heard about Async/Await keywords in other languages such as JavaScript or Dart, and how we use them for asynchronous programming. In this article we'll see how to utilize them and write asynchronous program.

# What is Asynchronous Programming?
Computer programs are typically synchronously on a single thread, this implies that that one task must complete before another task runs. This can be fine in small programs that doesn't do any form of I/O.

Asynchronous programming has to do with writing programs that executes multiple tasks concurrently in order not to leave the CPU idle.

# Why write Asynchronous code?
Let's assume that we write a program that fetches data from a web service, the program fetches a list of users and a list of latest posts.

    def fetch_posts():
        result = request('url')
        display(result)

    def fetch_users():
        result = request('url')
        display(result) 

    def main():
        fetch_posts()
        fetch_users()

    main()

In the pseudo-code above, the code runs synchronously. Network requests usually take time to get a response, while the program is waiting a response the CPU lies idle. Let's assume a network request takes 2 secs to resolve it means that the above program will take a little above four seconds to resolve. But if we write the program asynchronously we can run the two tasks(`fetch_posts()` and `fetch_users()`) concurrently.

Lets see an example that emulates a synchronous approach and another example that take an asynchronous approach.

### Synchronous approach
{% gist https://gist.github.com/Victor-El/0f53406e048add971cee4ee4d94d5358 %}

If you run the above program it takes a little over three seconds to complete, that is because the `fetch_users()` function waits for the `fetch_posts()` function to complete before it starts running.

Let's look at an asynchronous way of writing the same program.

{% gist https://gist.github.com/Victor-El/8b33b95cc67b2c800766e170a7c12746 %}

The program above runs in approximately 2 secs as opposed to the 3 secs which the synchronous approach takes. In this case the difference seems small but when working on real world applications, the difference can be huge.

So, we all know how to write synchronous programs, lets see the APIs that enable us write asynchronous code in python.

# Writing Asynchronous code in python

### Event Loop
In order for us to write asynchronous code, we need an event loop. 

![Confused](https://media.giphy.com/media/a0FuPjiLZev4c/giphy.gif)

An event loop is a programming construct that waits for and dispatches events or messages in a program. The event loop is basically what executes each task in a single threaded application. The event loop can be found in the `asyncio` package.

### Coroutines
You also need a coroutine. What is a coroutine? A coroutine in python a function or method that can pause it's execution and resume at a later point. Any task that needs to be run asynchronously needs to be a coroutine. You define a coroutine with `async def`. Coroutines are awaitable and can not be executed by simply calling the function. Prior to Python 3.5 the `async` keyword was not available in python, coroutines were created as a generator functions decorated with `@asyncio.coroutine`. You can read more about them [here](https://www.geeksforgeeks.org/coroutine-in-python/).


### Let's see how they all work together.
One on the rules of writing asynchronous code is that coroutines can not contain blocking code. `time.sleep(secs)` is a blocking code. Using `time.sleep(secs)` in our asynchronous example will make it run synchronously. `asyncio.sleep(secs)` is not a blocking code. `asyncio.sleep(secs)` represents an asynchronous task that can be awaited. Trying to await a non-awaitable task results to en exception.
One common mistake people new to writing asynchronous in python make is forgetting to await coroutines and other awaitables.

As someone who has written a fair amount of JavaScript, I expected functions marked with `async` to behave exactly as the one in JavaScript.

#### Some differences between JavaScript and Python Async Functions.
_JavaScript async functions run on a seperate thread and returns to the main 
thread on completion but Python async functions run a single thread and only 
switch to another coroutine when an asynchronous I/O operation is encountered._


Consider this program.
{% replit @VictorEl/async %}

In this program I made the event loop switch to another coroutine after every 1000 count. When you run the program, you'll notice that the second coroutine finishes before the first. All coroutine should be awaiting something in order for your code to be asynchronous. Remember everything runs on a single thread, so it's your responsibility to manage it. You can play with the repl to get used to `async/await` and `asyncio`.

Here is the same program written using different `asyncio` API.
{% replit @VictorEl/oldasync %}


From the code above you can see that i didn't call `asyncio.get_event_loop()`, this is because `asyncio.run()` is equivalent to `loop = asyncio.get_event_loop()` and `loop.run_until_complete`.
One of the benefits of using `asyncio.gather()` over `asyncio.wait()` is the ease of getting return values of the coroutines. `asyncio.gather()` when awaited returns a list containing all return values.

Check out this [Stackoverflow question](https://stackoverflow.com/questions/32456881/getting-values-from-functions-that-run-as-asyncio-tasks) If you want to know how to get back your return value from your coroutines.

Check [this](https://cheat.readthedocs.io/en/latest/python/asyncio.html) out for a summary of commonly used `asyncio` APIs.
[`asyncio` documentation](https://docs.python.org/3/library/asyncio.html).

Thanks for reading and I hope you enjoyed the article.