38.6 From Generator Coroutines to async/await
The evolution from generator-based coroutines to the modern async/await syntax represents a significant paradigm shift in Python’s approach to asynchronous programming. While generators provided a clever and powerful foundation, they were ultimately a repurposing of a feature designed for iteration, not a purpose-built solution for concurrency. The async/await syntax, introduced in Python 3.5, offered a cleaner, more explicit, and less error-prone model. The Generator-Based Coroutine Pattern Before async/await, coroutines were implemented using generators. A function containing a yield expression could be paused, and its execution could be controlled via .send(), .throw(), and .close() methods. This made it possible to build event loops that managed many such generators concurrently.