Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lära How the Event Loop Works | The Asyncio Foundation
Python Asyncio in Depth

How the Event Loop Works

Svep för att visa menyn

Everything in asyncio runs inside an event loop – a continuously running cycle that decides what runs next.

The Loop's Job

The event loop maintains a list of tasks. On each cycle, it:

  • Checks which tasks are ready to run;
  • Runs them until they hit an await;
  • Moves to the next ready task while the previous one waits.

No task ever truly runs in parallel. The loop gives each task a turn, switching between them at await points.

A Concrete Example

httpbin.org/delay/{n} is a public API that waits n seconds before responding – perfect for observing how the event loop handles slow operations.

12345678910111213141516171819202122232425262728293031
import asyncio import httpx import time import nest_asyncio nest_asyncio.apply() # Fetching from a slow endpoint to observe event loop scheduling async def fetch_slow(client, source, delay): print(f"Starting fetch from {source}") url = f"https://httpbin.org/delay/{delay}" response = await client.get(url) response.json() print(f"Done fetching from {source}") return f"Data from {source}" async def main(): start_time = time.time() async with httpx.AsyncClient() as client: # Running two slow requests concurrently results = await asyncio.gather( fetch_slow(client, "source_A", 2), fetch_slow(client, "source_B", 2), ) elapsed_time = time.time() - start_time print(results) print(f"Total time: {elapsed_time:.2f}s") # ~2s, not ~4s asyncio.run(main())

Both requests start almost simultaneously. The event loop starts fetch_slow(..., "source_A", 2), hits await response.json(), and immediately starts fetch_slow(..., "source_B", 2) instead of waiting. After ~2 seconds, both finish.

What await Actually Does

When a coroutine hits await, it suspends itself and hands control back to the event loop. The loop then picks the next ready task. When the awaited operation completes, the suspended coroutine is put back in the queue.

This is the core mechanism of asyncio:

  • await = "I'm waiting, someone else can run now";
  • Event loop = the scheduler that decides who runs next;
  • Coroutine = a function that knows how to pause and resume.

One Thread, Multiple Tasks

The event loop runs in a single thread. This means:

  • No race conditions from simultaneous memory access;
  • No need for locks when reading or writing shared data;
  • But also: a blocking call (like time.sleep()) freezes the entire loop.
12345678910111213141516171819202122232425262728
import asyncio import time import nest_asyncio nest_asyncio.apply() async def bad_example(): print("Starting bad...") time.sleep(1) # Blocking — freezing the entire event loop print("Done bad") async def good_example(): print("Starting good...") await asyncio.sleep(1) # Non-blocking — keeping the loop running print("Done good") async def main(): print("=== bad_example (blocks the loop) ===") start_time = time.time() await asyncio.gather(bad_example(), bad_example()) print(f"Total time: {time.time() - start_time:.2f}s\n") # ~2s print("=== good_example (non-blocking) ===") start_time = time.time() await asyncio.gather(good_example(), good_example()) print(f"Total time: {time.time() - start_time:.2f}s") # ~1s asyncio.run(main())

Always use asyncio.sleep() instead of time.sleep() inside async code. This pattern – using async-aware versions of blocking operations – runs throughout the entire asyncio ecosystem.

question mark

What happens when a coroutine hits an await expression?

Vänligen välj det korrekta svaret

Var allt tydligt?

Hur kan vi förbättra det?

Tack för dina kommentarer!

Avsnitt 1. Kapitel 3

Fråga AI

expand

Fråga AI

ChatGPT

Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal

Avsnitt 1. Kapitel 3
some-alt