Concurrencycritical

asyncio & Event Loop

A single-threaded concurrency model using an event loop that drives coroutines. Coroutines cooperatively yield control at await points.

Memory anchor

asyncio = an air traffic controller on a single runway. Planes (coroutines) take off and land cooperatively. One plane hogging the runway (blocking call) means every other plane circles forever.

Expected depth

asyncio.run(main()) starts the event loop. asyncio.create_task() schedules a coroutine to run concurrently on the same loop. asyncio.gather(*coros) runs multiple coroutines and collects results. Blocking calls (time.sleep, file reads) must be wrapped with loop.run_in_executor() to avoid blocking the event loop. aiohttp and asyncpg are async-native HTTP/DB clients.

Deep — senior internals

The event loop is a selector-based I/O multiplexer (select/epoll/kqueue under the hood). When a coroutine awaits an I/O operation, it registers a callback with the selector and yields. The loop runs the next ready coroutine. When I/O completes, the selector fires the callback and the coroutine resumes. asyncio.create_task() wraps a coroutine in a Task object that the loop drives. Python 3.11 added asyncio.TaskGroup for structured concurrency — tasks in the group share a lifetime and cancel together on exception. asyncio.Semaphore controls concurrency limits. asyncio.Queue enables producer-consumer patterns.

🎤Interview-ready answer

asyncio is a single-threaded cooperative concurrency model. The event loop runs coroutines that voluntarily yield at await points — there's no preemption. This makes it extremely efficient for I/O-bound workloads with many concurrent connections because there's no thread-switching overhead or locking. The limit: a blocking call in any coroutine stalls every other coroutine. Use run_in_executor() to offload blocking work to a thread pool. For CPU-bound work, asyncio doesn't help — use multiprocessing.

Common trap

Forgetting await is silent: result = some_async_fn() assigns the coroutine object, not the result. Python 3.4+ warns about unawaited coroutines, but it's easy to miss. Always await coroutines.

Related concepts