From 13565f15805c20d3aba42a123cdeeda91e67a603 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:10:05 +0200 Subject: [PATCH] [3.12] gh-108951: Document how to terminate an asyncio.TaskGroup (GH-123837) (#123957) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-108951: Document how to terminate an asyncio.TaskGroup (GH-123837) We don't want to add another API, since the recipe is straightforward and rarely needed. The advantage is that we could backport this to the earliest Python version that has taskgroups (3.11, alas in security mode already, so we'll just do 3.12 and 3.13). (cherry picked from commit ef05801ba0cbf090034df17e2a0420fb42c2d538) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/asyncio-task.rst | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 48cd2f247ad..e9b45cd2967 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -386,6 +386,53 @@ The same special case is made for :exc:`KeyboardInterrupt` and :exc:`SystemExit` as in the previous paragraph. +Terminating a Task Group +------------------------ + +While terminating a task group is not natively supported by the standard +library, termination can be achieved by adding an exception-raising task +to the task group and ignoring the raised exception: + +.. code-block:: python + + import asyncio + from asyncio import TaskGroup + + class TerminateTaskGroup(Exception): + """Exception raised to terminate a task group.""" + + async def force_terminate_task_group(): + """Used to force termination of a task group.""" + raise TerminateTaskGroup() + + async def job(task_id, sleep_time): + print(f'Task {task_id}: start') + await asyncio.sleep(sleep_time) + print(f'Task {task_id}: done') + + async def main(): + try: + async with TaskGroup() as group: + # spawn some tasks + group.create_task(job(1, 0.5)) + group.create_task(job(2, 1.5)) + # sleep for 1 second + await asyncio.sleep(1) + # add an exception-raising task to force the group to terminate + group.create_task(force_terminate_task_group()) + except* TerminateTaskGroup: + pass + + asyncio.run(main()) + +Expected output: + +.. code-block:: text + + Task 1: start + Task 2: start + Task 1: done + Sleeping ========