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

How the Event Loop Works

Scorri per mostrare il menu

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?

Seleziona la risposta corretta

Tutto è chiaro?

Come possiamo migliorarlo?

Grazie per i tuoi commenti!

Sezione 1. Capitolo 3

Chieda ad AI

expand

Chieda ad AI

ChatGPT

Chieda pure quello che desidera o provi una delle domande suggerite per iniziare la nostra conversazione

Sezione 1. Capitolo 3
some-alt