# Python asyncio internals **Python asyncio internals** refer to the event loop and task scheduling that power async/await. The event loop repeatedly polls I/O operations and runs ready coroutines, allowing thousands of concurrent connections with minimal threads. Understanding the event loop helps debug async behavior and write efficient concurrent code. Use asyncio for network I/O, concurrent file operations, or coordinating many independent tasks without threading overhead. ## Example This example shows the event loop, tasks, and concurrent execution. ```python # run: python3 asyncio_internals.py # description: asyncio event loop and task scheduling import asyncio import time async def fetch(url, delay): """Simulated async fetch.""" print(f"Starting fetch from {url}") await asyncio.sleep(delay) # yield control to event loop print(f"Finished fetch from {url}") return f"Data from {url}" async def main(): # Create tasks (scheduled coroutines) start = time.time() # Sequential: slow # result1 = await fetch("url1", 1) # result2 = await fetch("url2", 1) # Concurrent: fast - both run at once task1 = asyncio.create_task(fetch("url1", 1)) task2 = asyncio.create_task(fetch("url2", 1)) result1 = await task1 result2 = await task2 elapsed = time.time() - start print(f"Completed in {elapsed:.2f}s (concurrent, not sequential)") print(f"Results: {result1}, {result2}") # Get or create event loop and run asyncio.run(main()) # Event loop internals async def show_event_loop(): loop = asyncio.get_event_loop() print(f"\nEvent loop type: {type(loop)}") print(f"Running: {loop.is_running()}") # Create multiple tasks tasks = [ asyncio.create_task(asyncio.sleep(0.1 * i, result=f"Task {i}")) for i in range(1, 4) ] # Wait for all tasks results = await asyncio.gather(*tasks) print(f"All tasks done: {results}") asyncio.run(show_event_loop()) # Timeouts and cancellation async def with_timeout(): try: await asyncio.wait_for(asyncio.sleep(5), timeout=1) except asyncio.TimeoutError: print("Task timed out") # Cancellation task = asyncio.create_task(asyncio.sleep(10)) await asyncio.sleep(0.1) task.cancel() try: await task except asyncio.CancelledError: print("Task was cancelled") asyncio.run(with_timeout()) ``` ## Common patterns **Event loop**: - Single-threaded loop that alternates between: - Running ready coroutines - Polling I/O (waiting for network, disk, timers) - Running callbacks - `asyncio.run()` creates, runs, and closes loop - `asyncio.get_event_loop()` gets current loop (inside async function) **Tasks**: - `asyncio.create_task(coro)`: schedule coroutine on event loop - Returns immediately with Task object - Task runs when event loop runs - `await task` waits for completion **Concurrent execution**: - Multiple `await asyncio.sleep()` at same point are concurrent - Event loop interleaves them - No threads needed; single thread with efficient switching **Synchronization**: - `await asyncio.gather(*tasks)`: wait for all - `await asyncio.wait(tasks)`: low-level, returns done/pending - `async with asyncio.Lock():`: mutual exclusion - `async with asyncio.Semaphore(5):`: limit concurrent access **Error handling**: - Exceptions in tasks stored; raise when awaited - `await asyncio.gather(..., return_exceptions=True)`: collect errors - `task.exception()`: get exception without re-raising **Cancellation**: - `task.cancel()`: request cancellation - Raises `asyncio.CancelledError` inside task - Task should handle and clean up - `CancelledError` is subclass of `BaseException` (Python 3.8+) **Timeouts**: - `await asyncio.wait_for(coro, timeout=5)`: raises TimeoutError - Cancels coroutine if it times out **Callbacks and futures** (low-level): - `loop.call_soon(func)`: schedule function to run ASAP - `asyncio.Future()`: low-level promise object - Most code uses async/await, not callbacks/futures