Let’s learn how to do asynchronous programming in Python using the asyncio
module.
Asynchronous programming in this context refers to the programming paradigm where distinctive units of codes execute in parallel instead of sequentially. Asynchronous programming is particularly useful for cases where your application has to wait for the result of requests sent to external resources such as databases, webpages, REST APIs etc. With asynchronous programming, you can write applications that are more responsive and user-friendly.
There are several ways to implement asynchronous functions in Python, including via multithreading, multiprocessing, and other multitasking techniques. In addition to these, the default Python installation comes with a module called asyncio
that allows you to write asynchronous function at the programming level in Python. Today we’re going to show you how to do it.
Basic Python Asynchronous Programming with Asyncio
The following script imports the asyncio
module and then defines two functions: parent_func()
and child_func1()
. Notice the keyword async
before the function definition. You need to use this keyword to define asynchronous functions with the asyncio
module.
Inside the parent_func()
function, which we’ll refer to as parent function in this tutorial, the function child_func1()
is called asynchronously using the create_task()
method from the asyncio
module. The child_func1()
function will start executing whenever the parent_func()
is stuck and waiting for the result of some external request.
Next, inside the parent_func()
function you print a statement “Item 1” and then add a sleep of 2 seconds using the asyncio.sleep()
method. This sleep()
function is called to imitate the behavior where a function is waiting for the result of a request sent to an external resource. As soon as the sleep()
function executes the parent_func()
goes to the wait state and the child_func1()
starts executing. The child function prints two strings on the console.
After two seconds, the parent_func()
again starts executing which prints the string “Item 2” on the console. Set up your functions with this code:
import asyncio
async def parent_func():
#function to call if current function
#is waiting for something
task = asyncio.create_task(child_func1())
print("Item 1")
#add sleep to add a dummy wait
await asyncio.sleep(2)
print("Item 2")
async def child_func1():
print("Price 1")
print("Price 2")
To run an asynchronous function, you need to pass that functions call statement as a parameter value to the run()
method of the asyncio
module as shown below.
asyncio.run(parent_func())
Warning: If you’re testing this in Jupyter notebook or IPython, there’s a good chance the run
statement above will generate a *RuntimeError: asyncio.run() cannot be called from a running event loop” error. That’s because Jupyter is already running an event loop. You’ll need to replace the line above with await(parent_func())
.
The output below shows that the parent_func()
function prints the string “Item 1” on the console and then it goes to sleep for 2 seconds. During those 2 seconds, the child_func1()
executes in parallel and prints strings “Price 1” and “Price 2” on the console. Finally, after 2 seconds, the parent_func()
again starts executing and prints the string “Item 2” on the console.
Output:
Item 1
Price 1
Price 2
Item 2
Code More, Distract Less: Support Our Ad-Free Site
You might have noticed we removed ads from our site - we hope this enhances your learning experience. To help sustain this, please take a look at our Python Developer Kit and our comprehensive cheat sheets. Each purchase directly supports this site, ensuring we can continue to offer you quality, distraction-free tutorials.
Waiting for a Function Execution using Await keyword
In the previous section, you use the await
keyword to implement the sleep()
function inside the parent_func()
function. The await
keyword can also be used to wait for a function to complete its execution before the parent function completes its execution.
Let’s see an example where one asynchronous function completes execution without letting the other asynchronous function finish its execution.
The following script is similar to the previous script except for the third line in the child_func1()
function where we add a sleep of 4 seconds before the second print statement.
Now if you call the parent_func()
function using the run()
method from the asyncio
module, the string “Item 1” will be printed on the console, next the parent_func()
will sleep for 2 seconds and during that period the asynchronous function child_func1()
executes, printing the string “Price 1” on the console. It then sleeps for 4 seconds. After 2 seconds of sleep, the parent_func()
again starts executing and prints the string “Item 2” on the console and finishes execution.
Since the sleep time for the function child_func1()
is 4 seconds, the second print statement in the child_func1
function, which prints the string “Price 2” is not executed and you’ll only see three strings in the output of the following script.
import asyncio
async def parent_func():
#function to call if current function
#is waiting for something
task = asyncio.create_task(child_func1())
print("Item 1")
#add sleep to add a dummy wait
await asyncio.sleep(2)
print("Item 2")
async def child_func1():
print("Price 1")
#add sleep to add dummy wait for 4 seconds
await asyncio.sleep(4)
print("Price 2")
asyncio.run(parent_func())
Output:
Item 1
Price 1
Item 2
If you want your parent asynchronous function to not finish until the child asynchronous functions complete execution, you need to use the await
keyword before the child asynchronous function handler.
In the following script, the handler for the asynchronous function child_func1()
is assigned to the parent_func()
, the await
keyword is used before the child_func1()
to complete its execution. This all sounds complicated but it’s easier to understand when you look at the code below.
This time you’ll see that the child_func1()
completes its execution and the string “Price 2” is now printed on the console.
import asyncio
async def parent_func():
#function to call if current function
#is waiting for something
task = asyncio.create_task(child_func1())
print("Item 1")
#add sleep to add a dummy wait
await asyncio.sleep(2)
print("Item 2")
#wait for asynchronous function return
await task
async def child_func1():
print("Price 1")
#add sleep to add dummy wait for 4 seconds
await asyncio.sleep(4)
print("Price 2")
asyncio.run(parent_func())
Output:
Item 1
Price 1
Item 2
Price 2
Returning Values from Asynchronous Functions
You can also return values from an asynchronous function just like any other function. To do so, you have to use the return
keyword inside the asynchronous function. In the calling function, you need to use the await
keyword with the function handler for the child asynchronous function which will return the value returned by the asynchronous function.
In the following script, the child_func1()
returns a string “Price 3” to the calling function parent_func()
which it stores in the
import asyncio
async def parent_func():
#function to call if current function
#is waiting for something
task = asyncio.create_task(child_func1())
print("Item 1")
#add sleep to add a dummy wait
await asyncio.sleep(2)
print("item 2")
#wait for asynchronous function return
value = await task
print(value)
async def child_func1():
print("Price 1")
print("Price 2")
return "Price 3"
asyncio.run(parent_func())
Output:
Item 1
Price 1
Price 2
item 2
Price 3
I hope you found this tutorial helpful! Try these scripts and see what you can build. To get a free Python tutorial like this each week, subscribe using the form below.
Code More, Distract Less: Support Our Ad-Free Site
You might have noticed we removed ads from our site - we hope this enhances your learning experience. To help sustain this, please take a look at our Python Developer Kit and our comprehensive cheat sheets. Each purchase directly supports this site, ensuring we can continue to offer you quality, distraction-free tutorials.