In synchronous programming, tasks are executed sequentially, which means that the lower statement will be executed only after the upper statements are executed. For example:
1
2
3
4
5
def abc():
return
abc()
print("Hello")
The print statement will only be executed after the function is called and executed.
Let us now examine what async means. The simplest definition of async is “a style of concurrent programming”. Put another way, asynchronous programming is a type of parallel programming in which the tasks are executed without dependence on other tasks or the primary thread. The advantage of asynchronous programming is that program execution time will be shorter as compared to synchronous programming.
Asyncio is a built-in Python library used to write concurrent, asynchronous, and cooperative code in a sequential style.
A program is called concurrent when multiple tasks are running and overlapping each other’s lifecycle. In other words, we can switch from one task to another task for execution and then switch back to it concurrently. Whereas in parallelism the tasks run simultaneously.
Asyncio is a built-in library of Python to write concurrent code using async/await syntax. This library provides high-performance network and web servers, database connection libraries, distributed task queues, etc., for asynchronous programming.
A coroutine is a variant of a function that enables concurrency via cooperative multitasking. Coroutines are computer program components that generalize subroutines for non-preemptive multitasking by allowing execution to be suspended and resumed. We use the async keyword before defining a function, which creates a wrapper around this function. When it’s called, it returns a coroutine object which then needs to be executed. We then use the await keyword to execute the coroutine object (function).
For example,
1
2
3
4
5
6
import asyncio
async def main():
print("Hello")
main()
If I run the above code, it returns an error since I haven’t used the keyword await while calling the function main(). The error is:
RuntimeWarning: coroutine ‘main’ was never awaited
In another way, if I print the below statement,
print(main())
the result will be a coroutine object as shown below.
<coroutine object main 0x00000000026DACC0>
In order to execute the above code with async and await we are going to use an event loop.
To execute a coroutine, pass it to the asyncio.run() function.
asyncio.run(my_coroutine())
Example
1
2
3
4
5
6
import asyncio
async def main():
print("Welcome")
asyncio.run(main())
The above code prints the message ‘hello’ on running. Asyncio creates an event loop that allows us to run the program and closes it at the end.
In order to pause the execution we use the keyword “await” inside of the async function.
1
2
async def main():
await awaitable - object
Awaitable objects are coroutines,tasks, and futures.
In order to block a coroutine for a number of seconds we use asyncio.sleep. This suspends the current task, allowing other tasks to run.
Example
1
2
3
4
5
6
7
8
9
10
11
12
import asyncio
async def main():
print("old name is John")
await new('Harry')
async def new(name):
await asyncio.sleep(2)
print('new name is :')
print(name)
asyncio.run(main())
In the above example, we are using asyncio.sleep(2) in the new function which means that we are pausing the execution for two seconds. We are then calling this function inside of the main() function. Here you can observe that the message “new name is Harry” will be printed after two seconds of delay.
An event loop is the core of the asyncio application that takes care of all the running tasks. The event loop supports multitasking. When a function is suspended, control returns to the loop, which then finds another function to start or resume.
1 2 3
loop = asyncio.get_event_loop() loop.run_until_complete(my_coroutine()) loop.close()
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import asyncio
import time
async def cor1():
print("cor 1 started")
for i in range(5):
await asyncio.sleep(1.5)
print("cor1", i)
async def cor2():
print("cor 2 started")
for i in range(8):
await asyncio.sleep(1)
print("cor2", i)
loop = asyncio.get_event_loop()
cors = asyncio.wait([cor1(), cor2()])
loop.run_until_complete(cors)
Output
cor 2 started
cor 1 started
cor2 0
cor1 0
cor2 1
cor2 2
cor1 1
cor2 3
cor1 2
cor2 4
cor1 3
cor2 5
cor2 6
cor1 4
cor2 7
Tasks are used to schedule coroutines concurrently. We create a task using the function create_task(). The coroutine is wrapped into a task using this function.
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import asyncio
import time
async def main():
# Using asyncio.create_task() method to create a task
task1 = asyncio.create_task(foo('task 1'))
task2 = asyncio.create_task(foo('task 2'))
print(f "started at {time.strftime('%X')}")
# Wait until both tasks are completed
await task1
await task2
print(f "finished at {time.strftime('%X')}")
async def foo(text):
print(text)
await asyncio.sleep(1)
asyncio.run(main())
Output
started at 14:54:06
task 1
task 2
finished at 14:54:08
To perform concurrent execution, we use the function gather as follows.
awaitable asyncio.gather(*aws, return_exceptions=False)
This function takes any number of awaitables (coroutine, task, etc.) as an argument.
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import asyncio
async def printing(task, text):
while True:
print(task, text)
try:
await asyncio.sleep(0.50)
except asyncio.CancelledError:
break
async def main():
try:
await asyncio.wait_for(
asyncio.gather(
printing("A", "Message"),
printing("B", "Calling"),
printing("C", "Meeting")
), 3, )
except asyncio.TimeoutError:
print("Time over")
asyncio.run(main())
Asynchronous programming improves application performance and responsiveness. Python offers different libraries that support asynchronous programming. In this article, we have discussed the basic concepts in the asyncio library. This library lets us write concurrent code using the async/await syntax. Asyncio consists of high-level APIs such as coroutines, tasks, streams, subprocesses, exceptions, etc., and low-level APIs such as event loops, futures, transports, and protocols, etc. You can refer to the documentation at https://docs.python.org/3/library/asyncio.html to learn more advanced concepts and functions around the async and await keywords and also about the asyncio library.