diff options
author | Guido van Rossum <guido@python.org> | 2024-04-09 15:17:28 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-09 15:17:28 (GMT) |
commit | fa58e75a8605146a89ef72b58b4529669ac48366 (patch) | |
tree | 1e15a0af9593b52529a6e637703ea878d6d295e0 /Doc | |
parent | 22b25d1ebaab7b8c4833a8c120c8b4699a830f40 (diff) | |
download | cpython-fa58e75a8605146a89ef72b58b4529669ac48366.zip cpython-fa58e75a8605146a89ef72b58b4529669ac48366.tar.gz cpython-fa58e75a8605146a89ef72b58b4529669ac48366.tar.bz2 |
gh-116720: Fix corner cases of taskgroups (#117407)
This prevents external cancellations of a task group's parent task to
be dropped when an internal cancellation happens at the same time.
Also strengthen the semantics of uncancel() to clear self._must_cancel
when the cancellation count reaches zero.
Co-Authored-By: Tin Tvrtković <tinchester@gmail.com>
Co-Authored-By: Arthur Tacca
Diffstat (limited to 'Doc')
-rw-r--r-- | Doc/library/asyncio-task.rst | 30 | ||||
-rw-r--r-- | Doc/whatsnew/3.13.rst | 34 |
2 files changed, 57 insertions, 7 deletions
diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 3b10a0d..3d300c3 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -392,6 +392,27 @@ is also included in the exception group. The same special case is made for :exc:`KeyboardInterrupt` and :exc:`SystemExit` as in the previous paragraph. +Task groups are careful not to mix up the internal cancellation used to +"wake up" their :meth:`~object.__aexit__` with cancellation requests +for the task in which they are running made by other parties. +In particular, when one task group is syntactically nested in another, +and both experience an exception in one of their child tasks simultaneously, +the inner task group will process its exceptions, and then the outer task group +will receive another cancellation and process its own exceptions. + +In the case where a task group is cancelled externally and also must +raise an :exc:`ExceptionGroup`, it will call the parent task's +:meth:`~asyncio.Task.cancel` method. This ensures that a +:exc:`asyncio.CancelledError` will be raised at the next +:keyword:`await`, so the cancellation is not lost. + +Task groups preserve the cancellation count +reported by :meth:`asyncio.Task.cancelling`. + +.. versionchanged:: 3.13 + + Improved handling of simultaneous internal and external cancellations + and correct preservation of cancellation counts. Sleeping ======== @@ -1369,6 +1390,15 @@ Task Object catching :exc:`CancelledError`, it needs to call this method to remove the cancellation state. + When this method decrements the cancellation count to zero, + the method checks if a previous :meth:`cancel` call had arranged + for :exc:`CancelledError` to be thrown into the task. + If it hasn't been thrown yet, that arrangement will be + rescinded (by resetting the internal ``_must_cancel`` flag). + + .. versionchanged:: 3.13 + Changed to rescind pending cancellation requests upon reaching zero. + .. method:: cancelling() Return the number of pending cancellation requests to this Task, i.e., diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 707dcaa..d971beb 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -196,13 +196,6 @@ Other Language Changes (Contributed by Sebastian Pipping in :gh:`115623`.) -* When :func:`asyncio.TaskGroup.create_task` is called on an inactive - :class:`asyncio.TaskGroup`, the given coroutine will be closed (which - prevents a :exc:`RuntimeWarning` about the given coroutine being - never awaited). - - (Contributed by Arthur Tacca and Jason Zhang in :gh:`115957`.) - * The :func:`ssl.create_default_context` API now includes :data:`ssl.VERIFY_X509_PARTIAL_CHAIN` and :data:`ssl.VERIFY_X509_STRICT` in its default flags. @@ -300,6 +293,33 @@ asyncio with the tasks being completed. (Contributed by Justin Arthur in :gh:`77714`.) +* When :func:`asyncio.TaskGroup.create_task` is called on an inactive + :class:`asyncio.TaskGroup`, the given coroutine will be closed (which + prevents a :exc:`RuntimeWarning` about the given coroutine being + never awaited). + (Contributed by Arthur Tacca and Jason Zhang in :gh:`115957`.) + +* Improved behavior of :class:`asyncio.TaskGroup` when an external cancellation + collides with an internal cancellation. For example, when two task groups + are nested and both experience an exception in a child task simultaneously, + it was possible that the outer task group would hang, because its internal + cancellation was swallowed by the inner task group. + + In the case where a task group is cancelled externally and also must + raise an :exc:`ExceptionGroup`, it will now call the parent task's + :meth:`~asyncio.Task.cancel` method. This ensures that a + :exc:`asyncio.CancelledError` will be raised at the next + :keyword:`await`, so the cancellation is not lost. + + An added benefit of these changes is that task groups now preserve the + cancellation count (:meth:`asyncio.Task.cancelling`). + + In order to handle some corner cases, :meth:`asyncio.Task.uncancel` may now + reset the undocumented ``_must_cancel`` flag when the cancellation count + reaches zero. + + (Inspired by an issue reported by Arthur Tacca in :gh:`116720`.) + * Add :meth:`asyncio.Queue.shutdown` (along with :exc:`asyncio.QueueShutDown`) for queue termination. (Contributed by Laurie Opperman and Yves Duprat in :gh:`104228`.) |