AsyncIO: Single-Threaded Concurrency
AsyncIO is modern Python’s answer to the challenge of building high-performance network applications. While threading and multiprocessing rely on the operating system to switch between tasks, AsyncIO uses Cooperative Multitasking.
In an AsyncIO program, a single thread runs an “Event Loop” that switches between tasks only when a task is waiting for I/O (like a database query or a web request).
1. Coroutines: async and await
Section titled “1. Coroutines: async and await”A Coroutine is a specialized generator that can pause and resume.
async def: Defines a coroutine. Calling it returns a coroutine object, but doesn’t run the code.await: Pauses the current coroutine and yields control back to the event loop until the result is ready.
import asyncio
async def fetch_api(): print("Requesting data...") await asyncio.sleep(1) # Non-blocking wait print("Data received!") return {"status": 200}
# Run the coroutineresult = asyncio.run(fetch_api())2. The Event Loop
Section titled “2. The Event Loop”Think of the Event Loop as a traffic controller. It keeps a list of all active coroutines.
- It runs Coroutine A until it hits an
await. - If Coroutine A is waiting for a network response, the loop parks it and switches to Coroutine B.
- As soon as the network response for A arrives, the loop resumes A where it left off.
Creating Concurrent Tasks
Section titled “Creating Concurrent Tasks”If you just await one thing after another, your code is still sequential. To run things at the same time, you must create Tasks.
async def main(): # Schedule two tasks to run concurrently task1 = asyncio.create_task(fetch_api()) task2 = asyncio.create_task(fetch_api())
# Wait for both to finish val1 = await task1 val2 = await task23. The “Golden Rule” of AsyncIO
Section titled “3. The “Golden Rule” of AsyncIO”4. Under the Hood: Why AsyncIO?
Section titled “4. Under the Hood: Why AsyncIO?”Why use AsyncIO if it only uses one core? Efficiency.
- Low RAM: A thread consumes about 8MB of RAM for its stack. A coroutine consumes only about 2KB. You can run 100,000 coroutines on a laptop, but you can’t run 100,000 threads.
- No Race Conditions: Since everything runs in one thread, you don’t need Locks for most simple variables. (Though you still need to be careful with shared resources across
awaitpoints).
5. Summary Table
Section titled “5. Summary Table”| Feature | Sync Code | AsyncIO |
|---|---|---|
| Logic | Top to bottom. | Cooperative (yields control). |
| I/O Handling | Stops everything until done. | Switches tasks while waiting. |
| Keyword | def | async def |
| Wait Command | result = call() | result = await call() |