The asyncio await expression allows a coroutine to be suspended until a specified awaitable is done.
In this tutorial, you will discover the asyncio await expression in Python.
Let’s get started.
What is await
In asyncio, await is a keyword and expression.
It is used within a coroutine to yield execution to an awaitable.
Await expression: Suspend the execution of coroutine on an awaitable object. Can only be used inside a coroutine function.
— Python Expressions
An awaitable may be another coroutine or a coroutine wrapped in a Task object for independent execution.
An object that can be used in an await expression. Can be a coroutine or an object with an __await__() method.
— Python Glossary
Put another way, await will cause the caller coroutine to suspend execution at that point and wait for the given awaitable to be done.
An awaitable is done if it finishes normally, returns explicitly, is canceled or fails with an error or exception.
Run loops using all CPUs, download your FREE book to learn how.
How to Use await
The await expression can be used by using the “await” keyword followed by an awaitable.
For example:
1 2 3 |
... # await a coroutine await custom_coroutine() |
This line does a few things.
Firstly, it creates a coroutine object.
It then schedules the coroutine for execution in the asyncio event loop.
The caller then suspends execution and waits for the new coroutine to be done.
The awaitable coroutine may return a value that we may want after the awaitable is done.
This can be assigned as part of the await expression.
For example:
1 2 3 |
... # await a coroutine and store the return value value = await custom_coroutine() |
Another awaitable is a task, that allows the independent execution of a coroutine and provides a handle on its execution.
We can create a task via the asyncio.create_task() function that takes a coroutine, then await the task object directly.
For example:
1 2 3 |
... # await a task await asyncio.create_task(custom_coroutine()) |
Next, let’s consider why we would use await.
Why use await
We would use an await expression within a coroutine.
This would be done to explicitly wait for some condition, such as:
- Wait for a coroutine to be done.
- Wait for a task to be done.
- Wait for a return value from a task or coroutine.
Another reason we may want to await from within a coroutine is to allow another coroutine or coroutine an opportunity to run.
We can easily schedule coroutines to execute independently as tasks, but a coroutine or task will not execute until all other coroutines and tasks are not running, such as done or waiting.
Therefore, we may explicitly call await only with the intention of allowing one or more other coroutines to run.
This is often achieved by awaiting an asyncio.sleep() operation that sleeps for zero seconds.
Setting the delay to 0 provides an optimized path to allow other tasks to run. This can be used by long-running functions to avoid blocking the event loop for the full duration of the function call.
— Coroutines and Tasks
This sends a signal to the asyncio event loop to execute another or other coroutines but to return control as soon as possible.
For example:
1 2 3 |
... # allow other coroutines to run await asyncio.sleep(0) |
Now that we know how to use the await expression, let’s compare it to some similar expressions.
Free Python Asyncio Course
Download your FREE Asyncio PDF cheat sheet and get BONUS access to my free 7-day crash course on the Asyncio API.
Discover how to use the Python asyncio module including how to define, create, and run new coroutines and how to use non-blocking I/O.
Await vs Yield
The await and yield expressions are very similar.
The await expression will wait for a given awaitable. Put another way, it will yield to an awaitable, like a coroutine.
The yield expression is used to define a generator. A function (routine) that has a yield expression might be called a generator function.
The yield expression is used when defining a generator function or an asynchronous generator function and thus can only be used in the body of a function definition.
— Python Expressions
It returns one value from the function and suspends execution until called again, where it will continue on from the same point.
For example:
1 2 3 4 |
# definition of a generator def custom_generator(): for i in range(10): yield i |
Here, we can see that the state of the for-loop is maintained and each time it is called it will return the current value of the loop. The state of the loop variable is maintained until the next time it is called where execution is resumed and one more loop iteration is executed.
Both do something and suspend execution and maintain the state:
- await will schedule and wait on a coroutine or wait on a task
- yield will return a value
Both will continue when control is returned.
- await receives control sometime after the awaitable is done.
- yield receives control the next time the outer function (routine) is called
Control is returned to a coroutine that is awaiting via the asyncio event loop. Control is returned to the yielded function via some external iteration of the generator, e.g. calls to next().
We can think of both a coroutine that awaits and a generator function that yields as having multiple entry points.
- A coroutine will be executed from the top down, but once it awaits, execution later resumes from that point, a second entry point.
- A generator function can be executed from the top down, but once it yields, execution later resumes from that point, also a second entry point.
Overwhelmed by the python concurrency APIs?
Find relief, download my FREE Python Concurrency Mind Maps
Further Reading
This section provides additional resources that you may find helpful.
Python Asyncio Books
- Python Asyncio Mastery, Jason Brownlee (my book!)
- Python Asyncio Jump-Start, Jason Brownlee.
- Python Asyncio Interview Questions, Jason Brownlee.
- Asyncio Module API Cheat Sheet
I also recommend the following books:
- Python Concurrency with asyncio, Matthew Fowler, 2022.
- Using Asyncio in Python, Caleb Hattingh, 2020.
- asyncio Recipes, Mohamed Mustapha Tahrioui, 2019.
Guides
APIs
- asyncio — Asynchronous I/O
- Asyncio Coroutines and Tasks
- Asyncio Streams
- Asyncio Subprocesses
- Asyncio Queues
- Asyncio Synchronization Primitives
References
Takeaways
You now know the asyncio await expression in Python.
Do you have any questions?
Ask your questions in the comments below and I will do my best to answer.
Photo by Kevin Bhagat on Unsplash
Do you have any questions?