Python for AIPython 3.10+ · Pydantic 2.12
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
34 small wins to finish your pathNext lesson →

async and await

async and await are the keywords for code that waits: async def defines a coroutine function, and await runs a coroutine and waits for its result.

Last updated: 30 Sep, 2026 · Python 3.14

A real model takes a second or more to answer, and nearly all of that time your program is waiting on the network. This lesson measures that wait, then writes the version that can share it.

Syntax:

python
import asyncio

async def work():
    await asyncio.sleep(1)   # wait without blocking

asyncio.run(work())          # start from ordinary code

Timing three slow calls

Example
import time

def ask_model_slowly(text):
    time.sleep(0.5)
    return f"answer to: {text}"

start = time.perf_counter()
for text in ["ticket 1", "ticket 2", "ticket 3"]:
    print(ask_model_slowly(text))
print(f"took {time.perf_counter() - start:.1f} seconds")

time.sleep(0.5) pauses for half a second, standing in for the network. time.perf_counter reads a clock, and :.1f in the f-string shows one digit after the point.

Three calls, half a second each, one after the other: a second and a half. A hundred tickets would take fifty seconds, nearly all of it waiting.

Writing the async version

Example
import asyncio

async def ask_model_slowly(text):
    await asyncio.sleep(0.5)
    return f"answer to: {text}"

async def main():
    for text in ["ticket 1", "ticket 2", "ticket 3"]:
        print(await ask_model_slowly(text))

asyncio.run(main())

async def makes a coroutine function: calling it does not run it straight away. await runs it and waits for the result, and while it waits, Python is free to work on something else.

await only works inside an async def. asyncio.run(main()) is the one line that starts the async part of a program from ordinary code.

This version is not faster yet. It still awaits one ticket before starting the next. What changed is that the waiting can now be shared, which asyncio.gather does.

Forgetting await

Example
async def main():
    answer = ask_model_slowly("ticket 1")
    print(answer)

asyncio.run(main())

There is no answer and no error, only a coroutine object: the work that was never started. Python also prints a RuntimeWarning: coroutine ... was never awaited to the error stream. When an async function seems to return something strange, look for a missing await first.

def vs async def

defasync def
Calling itRuns it and gives the resultGives a coroutine object
Getting the resultThe call itselfawait the call
Waiting inside ittime.sleep blocks everythingawait asyncio.sleep lets others run

Where async shows up in AI code

  • Model SDKs offer async clients, such as AsyncOpenAI, whose calls you await.
  • Agent frameworks run tools and model calls as coroutines.
  • Web servers such as FastAPI handle each request with async def.
Watch out. time.sleep inside an async def still blocks the whole program. Use await asyncio.sleep in async code, or the waits cannot overlap.
Try it yourself
  • Time the async version with time.perf_counter and confirm it takes about as long as the first one.
  • Change the sleep to 1 second and add a fourth ticket. Work out the time before you run it.
  • Add await back in front of ask_model_slowly in the last example.

You understood something today that you didn't yesterday.