Skip to content

Coroutines and await

coroutine_def.py
import asyncio
 
 
async def say_hi():
    await asyncio.sleep(0.1)
    return "hi"

Calling a coroutine function returns a coroutine object.

calling_vs_awaiting.py
import asyncio
 
 
async def say_hi():
    await asyncio.sleep(0.1)
    return "hi"
 
 
async def main():
    c = say_hi()          # coroutine object (NOT executed yet)
    msg = await say_hi()  # executed
    print(type(c))
    print(msg)
 
 
asyncio.run(main())
sketch Calling a coroutine function does not run it p5.js
A normal function call runs the body and returns a value. Calling an async def returns a coroutine OBJECT and runs nothing at all -- the body has not started. Only await drives it. This is the single most common asyncio mistake, and the giveaway is that your print statements never appear.

You can only use await inside an async def function.

If you need to run async code from normal code, use:

  • asyncio.run(main()) (most common)
sketch Every await is a place the loop can leave you p5.js
A coroutine is not interrupted at arbitrary points. It runs straight through until it reaches an await, and only then does control go back to the event loop, which is free to run something else before coming back. That is why asyncio needs no locks for ordinary code between awaits -- and why a blocking call with no await freezes everything.

This does nothing useful:

wrong.py
async def main():
    say_hi()  # forgot await

Because the coroutine is created but never awaited.

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading