Phase 13 of 25 · Topic 13.3

Structured Concurrency with asyncio.TaskGroup (Python 3.11+)

1Concept

Python 3.11 introduced `asyncio.TaskGroup` for structured concurrency. If any task inside the TaskGroup fails, all remaining sibling tasks are automatically cancelled immediately, and errors are packaged into an `ExceptionGroup`.

2Architecture Diagram

async with asyncio.TaskGroup() as tg:
  tg.create_task(Task A)
  tg.create_task(Task B) ---> If B throws, Task A is cancelled instantly! No orphaned tasks!

3Code Example

Python 3.12
import asyncio

async def background_worker(name: str):
    await asyncio.sleep(0.01)
    return f"Worker {name} finished"

async def main():
    results = []
    async with asyncio.TaskGroup() as tg:
        t1 = tg.create_task(background_worker("A"))
        t2 = tg.create_task(background_worker("B"))
    print(f"TaskGroup completed safely: {[t1.result(), t2.result()]}")

asyncio.run(main())

4Expected Output

TaskGroup completed safely: ['Worker A finished', 'Worker B finished']

5Key Takeaways

  • `TaskGroup` eliminates orphaned coroutine leaks when exceptions occur.
  • Awaits all scheduled tasks automatically upon exiting the `async with` block.
  • Replaces legacy `asyncio.gather()` as the best practice in Python 3.11+.