Python Central HubSign in

Python Programming / Python Asyncio

Coroutines and await

Learn async def coroutines, await, and the difference between calling and awaiting a coroutine.

async def creates a coroutine function

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

Calling vs awaiting

Calling a coroutine function returns a coroutine object.

Python
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.

await points

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.

Common mistake

This does nothing useful:

Python
async def main():
    say_hi()  # forgot await

Because the coroutine is created but never awaited.

Why coroutines exist

Most programs spend a lot of time waiting: for a web server to answer, a file to load, a database to reply. A normal function that waits blocks everything behind it. A coroutine is a function that can pause while it waits and let other work run, then resume exactly where it left off. You create one by writing async def, and you pause inside it with await.

Reading the two examples

In coroutine_def.py, say_hi waits 0.1 seconds with await asyncio.sleep(0.1) and then returns "hi". The return value is ordinary: when the coroutine is awaited, you get "hi" back just like from a normal function.

In calling_vs_awaiting.py, the important lines are these two:

  • c = say_hi() builds a coroutine object. The body has not started; you hold a plan, not a result. Python will even warn you that the coroutine was "never awaited".
  • msg = await say_hi() runs the body to completion, pausing at the sleep, and gives you the returned value.

Printing type(c) shows <class 'coroutine'>, which proves nothing ran.

Running two things at once

A plain await runs one coroutine after another. To overlap the waiting, schedule coroutines as tasks or gather them:

Python
import asyncio
import time
 
 
async def fetch(name: str, delay: float) -> str:
    await asyncio.sleep(delay)
    return f"{name} done"
 
 
async def main() -> None:
    start = time.perf_counter()
    results = await asyncio.gather(fetch("A", 0.3), fetch("B", 0.3))
    print(results)
    print(f"took about {time.perf_counter() - start:.1f}s")  # about 0.3, not 0.6
 
 
asyncio.run(main())

Two 0.3 second waits finish in roughly 0.3 seconds in total, because while A waits, the event loop runs B.

Common mistakes

  • Forgetting await. say_hi() alone does nothing. If your prints never appear, look for a missing await.
  • Using await in a normal function. It is a SyntaxError outside async def. Start the chain with asyncio.run(main()).
  • Blocking calls inside a coroutine. time.sleep(1) freezes the whole event loop. Use await asyncio.sleep(1) instead.
  • Calling asyncio.run inside a running loop. In notebooks, where a loop is already running, use await main() instead.

When to use it

Use coroutines for I/O-bound work with lots of waiting: many network requests, chat servers, scraping. They do not speed up heavy calculation; for that, use processes.

🧪 Try It Yourself

Exercise 1 – Your First Coroutine

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Exercise 2 – await asyncio.sleep

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Exercise 3 – Gather Two Coroutines

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Was this page helpful?

Let us know how we did