asyncio in Python

As programmers, you may be familiar with the concept of concurrency. Concurrent Programming is computer programming that allows multiple computations to happen at the same period of time. This lets you avoid the time spent waiting for another task to complete and is thus, often advantageous.
asyncio is a Python standard library for writing concurrent code. It is a concurrent programming design that eases the working of asynchronous codes by providing methods to write, execute and well structure your coroutines.

Read further to learn about asyncio and its usage in detail.

Introduction

Consider a web application that involves processing several requests coming from several different users within a short specified period of time. In such a case, if the second process has to wait until the completion of the first and so on, that would simply be unnecessary and a major loss of time.
This is where concurrent programming steps in by allowing the application to process more than one request simultaneously.

Asynchronous I/O, as the name suggests is an input-output model that permits a process to continue even before the termination of other/previous processes. In simple words, in Asynchronous I/O nothing is waiting for anything(any operation) to complete.
Different programming languages have different libraries and methods to facilitate the same. In Python programming, asyncio is the standard library for Asynchronous I/O operations by using async/await syntax.

Important Concepts for asyncio programming in  Python

Coroutines

Coroutines are general control functions used for cooperative tasks. They allow to suspend execution before reaching the return statement and to pass the control flow to different routines.
You can create a coroutine by using the async keyword before def in the method.

Let us create an example coroutine:

async def eg_coroutine():
    for i in range(200):
        print("Hello from Codespeedy!")

In order to call or execute a coroutine, you have to first schedule it on the Event loop. Otherwise, it can throw an error. Once scheduled, you can wrap them in Tasks as future objects.

Tasks

In order to run two or more coroutines simultaneously, it is important to schedule them in proper order. Tasks allow us to do the same.
When you process any particular coroutine, in the event loop, it returns a Task object for controlling the behavior of that routine.

import asyncio
async def eg_coroutine():
    print('Hello!')
    await asyncio.sleep(1)
    print('Welcome to CodeSpeedy!')
async def main():
    task = asyncio.create_task (eg_coroutine())
    await task
await main()
Hello!
Welcome to CodeSpeedy!

In the above code;

  • We have used asyncio’s create_task method to create a task for the coroutine.
    The create_task() manages the coroutines to run concurrently along with other tasks, switching between them on encountering await.

Note:
In some older versions of Python, you might face an error on using await
keyword to invoke the function.
In such a case, you can use the oldermethod, “asyncio.run(function_name)”
instead.
Eg: asyncio.run(main)

Event Loops

They are mechanisms to ensure that the coroutines run until their execution is complete. It monitors the execution of coroutines by checking into what processes are idle, what processes are running, waking up idle routines at the right time, avoiding unnecessary waiting etc.
Note: Python allows only a single event loop to execute at a single period of time.

Let us consider an example where we define an Event Loop to execute 3 tasks concurrently;

import asyncio
async def eg_coroutine(task_no):
    print(f'{task_no} :Hello!')
    await asyncio.sleep(1)
    print(f'{task_no} :Welcome to CodeSpeedy!!')
async def main():
    task1 = loop.create_task (eg_coroutine('task1'))
    task2 = loop.create_task(eg_coroutine('task2'))
    task3 = loop.create_task(eg_coroutine('task3'))
    await asyncio.wait([task1,task2,task3])
if __name__ == "__main__":
    try:
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())
    except :
        pass
task1 :Hello!
task2 :Hello!
task3 :Hello!
task1 :Welcome to CodeSpeedy!!
task2 :Welcome to CodeSpeedy!!
task3 :Welcome to CodeSpeedy!!

Here;

  • We have created 3 tasks task1, task2, task3 by using create_task() and appended them into a list using asyncio.wait().
  • The asyncio.get_event_loop() gets the current event loop. In the case where no current event loop is set in the current OS thread, the OS thread is main, and set_event_loop() is not yet called, asyncio will create a new event loop and set it as the current one.
  • The loop.run_until_complete() runs until the an instance of the future (coroutine object) has completed.Here, it runs until the main() is executed.
  • The keyword await of the asyncio library is used to transfer the flow control to the specified routine.

asyncio in Python: An Example Program

import asyncio
async def eg_coroutine1():
    for i in range(3):
        print("Hello!")
        print("Welcome to CodeSpeedy!")
        await asyncio.sleep(0.01)
    return 0
async def eg_coroutine2():
    print("See you again!")
    return 0
async def main():
    f1 = loop.create_task(eg_coroutine1())
    f2 = loop.create_task(eg_coroutine2())
    await asyncio.wait([f1, f2])
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
Hello!
Welcome to CodeSpeedy!
See you again!
Hello!
Welcome to CodeSpeedy!
Hello!
Welcome to CodeSpeedy!

 

There has always been a debate on the efficiencies of synchronous applications versus asynchronous ones. You can observe that concurrent programming allows sharing of resources, improves execution speed and increases scalability. However, async applications will do better than sync applications only when there is a high load.

Also, check out,

How to Achieve Parallel Processing in Python

Leave a Reply

Your email address will not be published.