gh-108951: Document how to terminate an asyncio.TaskGroup (#123837) · python/cpython@ef05801 (original) (raw)

Original file line number Diff line number Diff line change
@@ -414,6 +414,53 @@ reported by :meth:`asyncio.Task.cancelling`.
414 414 Improved handling of simultaneous internal and external cancellations
415 415 and correct preservation of cancellation counts.
416 416
417 +Terminating a Task Group
418 +------------------------
419 +
420 +While terminating a task group is not natively supported by the standard
421 +library, termination can be achieved by adding an exception-raising task
422 +to the task group and ignoring the raised exception:
423 +
424 +.. code-block:: python
425 +
426 + import asyncio
427 + from asyncio import TaskGroup
428 +
429 + class TerminateTaskGroup(Exception):
430 + """Exception raised to terminate a task group."""
431 +
432 + async def force_terminate_task_group():
433 + """Used to force termination of a task group."""
434 + raise TerminateTaskGroup()
435 +
436 + async def job(task_id, sleep_time):
437 + print(f'Task {task_id}: start')
438 + await asyncio.sleep(sleep_time)
439 + print(f'Task {task_id}: done')
440 +
441 + async def main():
442 + try:
443 + async with TaskGroup() as group:
444 + # spawn some tasks
445 + group.create_task(job(1, 0.5))
446 + group.create_task(job(2, 1.5))
447 + # sleep for 1 second
448 + await asyncio.sleep(1)
449 + # add an exception-raising task to force the group to terminate
450 + group.create_task(force_terminate_task_group())
451 + except* TerminateTaskGroup:
452 + pass
453 +
454 + asyncio.run(main())
455 +
456 +Expected output:
457 +
458 +.. code-block:: text
459 +
460 + Task 1: start
461 + Task 2: start
462 + Task 1: done
463 +
417 464 Sleeping
418 465 ========
419 466