GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Introduce task groups to asyncio and change task cancellation semantics · Issue #90908 · python/cpython

Introduce task groups to asyncio and change task cancellation semantics #90908

New issue
Copy link
New issue
Copy link
Closed
Closed
Introduce task groups to asyncio and change task cancellation semantics#90908
Copy link
Assignees
gvanrossum
Labels
3.11only security fixesonly security fixesdeferred-blockertopic-asyncio

Description

@gvanrossum
gvanrossum
opened on Feb 14, 2022
Issue body actions
BPO 46752
Nosy @gvanrossum, @njsmith, @asvetlov, @dhalbert, @1st1, @Tinche, @iritkatriel, @YvesDup
PRs
  • bpo-46752: Introduce task groups in asyncio #31270
  • bpo-46752: Slight improvements to TaskGroup API #31398
  • bpo-46752: Uniform TaskGroup.__repr__ #31409
  • bpo-46752: Reduce flakiness of taskgroups test 13 #31411
  • bpo-46771: Implement task cancel requests #31513
  • bpo-46752: Taskgroup tweaks #31559
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/gvanrossum'
    closed_at = None
    created_at = <Date 2022-02-14.20:44:29.619>
    labels = ['3.11', 'expert-asyncio']
    title = 'Introduce task groups to asyncio and change task cancellation semantics'
    updated_at = <Date 2022-02-25.15:33:21.072>
    user = 'https://github.com/gvanrossum'

    bugs.python.org fields:

    activity = <Date 2022-02-25.15:33:21.072>
    actor = 'yduprat'
    assignee = 'gvanrossum'
    closed = False
    closed_date = None
    closer = None
    components = ['asyncio']
    creation = <Date 2022-02-14.20:44:29.619>
    creator = 'gvanrossum'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 46752
    keywords = ['patch', 'needs review']
    message_count = 10.0
    messages = ['413260', '413305', '413306', '413335', '413344', '413346', '413348', '413353', '413467', '413577']
    nosy_count = 8.0
    nosy_names = ['gvanrossum', 'njs', 'asvetlov', 'dhalbert', 'yselivanov', 'tinchester', 'iritkatriel', 'yduprat']
    pr_nums = ['31270', '31398', '31409', '31411', '31513', '31559']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue46752'
    versions = ['Python 3.11']

    Reacted by dogisgreat

    Activity

    Next
    1. gvanrossum commented on Feb 14, 2022

      @gvanrossum
      gvanrossum
      on Feb 14, 2022
      MemberAuthor
      More actions

      After some conversations with Yury, and encouraged by the SC's approval of PEP-654, I am proposing to add a new class, asyncio.TaskGroup, which introduces structured concurrency similar to nurseries in Trio.

      I started with EdgeDb's TaskGroup implementation (https://github.com/edgedb/edgedb/blob/master/edb/common/taskgroup.py) and tweaked it only slightly. I also changed a few things in asyncio.Task (see below).

      The key change I made to EdgeDb's TaskGroup is that subtasks can keep spawning more subtasks while __aexit__ is running; __aexit__ exits once the last subtask is done. I made this change after consulting some Trio folks, who knew of real-world use cases for this behavior, and did not know of real-world code in need of prohibiting task creation as soon as __aexit__ starts running. I added some tests for the new behavior; none of the existing tests needed to be adjusted to accommodate this change.

      (For other changes relative to the EdgeDb's TaskGroup, see #75453.)

      In order to avoid the need to monkey-patch the parent task, I added two new methods to asyncio.Task, .cancelled() and .uncancel(), that manage a flag corresponding to __cancel_requested__ in EdgeDb's TaskGroup.

      **This introduces a change in behavior around task cancellation:**

      • A task that catches CancelledError is allowed to run undisturbed (ignoring further .cancel() calls and allowing any number of await calls!) until it either exits or calls .uncancel().

      This change in semantics did not cause any asyncio unittests to fail. However, it may be surprising (especially to Trio folks, where the semantics are pretty much the opposite, once a Trio task is cancelled all further await calls in that task fail unless explicitly shielded).

      For the TaskGroup tests to pass, we require a flag that is not cleared. However, it is probably not really required to ignore subsequent .cancel() calls until .uncancel() is called. This just seemed more consistent, and it is what @asvetlov proposed above and implemented in #75494 (using a property .__cancel_requested__ as the API).

      Reacted by Frederik Aalund and Hash
    2. gvanrossum
      added
      3.11only security fixesonly security fixes
      on Feb 14, 2022
    3. gvanrossum
      self-assigned this
      on Feb 14, 2022
    4. gvanrossum
      added
      topic-asyncio
      3.11only security fixesonly security fixes
      on Feb 14, 2022
    5. gvanrossum
      self-assigned this
      on Feb 14, 2022
    6. gvanrossum
      added
      topic-asyncio
      on Feb 14, 2022
    7. gvanrossum commented on Feb 15, 2022

      @gvanrossum
      gvanrossum
      on Feb 15, 2022
      MemberAuthor
      More actions

      New changeset 602630a by Guido van Rossum in branch 'main':
      bpo-46752: Add TaskGroup; add Task..cancelled(),.uncancel() (GH-31270)
      602630a

    8. gvanrossum commented on Feb 15, 2022

      @gvanrossum
      gvanrossum
      on Feb 15, 2022
      MemberAuthor
      More actions

      Remaining TODO list:

      • Add a test showing the need for the .uncancel() call in __aexit__()
        (currently on line 97). Dropping that line does not cause any tests
        to fail.
      • Ensure the taskgroup tests are run with the C and Python Task
        implementations.
      • Rename tests to have meaningful names.
      • I have a few ideas for minor cleanups that I will do later.
      • Documentation and What's New entry (in a separate PR, probably).
      • Update the docs in a few places to de-prioritize asyncio.gather()
        and steer people towards TaskGroups.

      (We could also add something like Trio's cancel scopes, e.g. based on
      Andrew Svetlov's async-timeout, which has a mature API.
      But that should be a separate bpo issue.)

    9. dhalbert commented on Feb 16, 2022

      @dhalbert
      dhalbertmannequin
      on Feb 16, 2022
      Mannequin
      More actions

      For your TODO list (not sure how else to communicate this):

      I agree with the de-emphasis of gather(). I think adding another version of gather() that cancels all the remaining tasks if one fails would also be good, unless you think it is completely redundant due to TaskGroups. This idea was originally mentioned in https://bugs.python.org/issue31452 as a bug, and determined to be "works as designed". So now making an all-cancel() version of gather() is an idiom that people keep recoding, e.g. https://stackoverflow.com/questions/59073556/how-to-cancel-all-remaining-tasks-in-gather-if-one-fails.

    10. gvanrossum commented on Feb 16, 2022

      @gvanrossum
      gvanrossum
      on Feb 16, 2022
      MemberAuthor
      More actions

      @dhalbert, it's probably better to file a new issue if you want changes to gather(). Although I suppose that if we want to deemphasize it, we shouldn't be adding new features to it. My own new feature idea would be to have it wait for all tasks and then if there are any exceptions, raise an ExceptionGroup. That (like any new gather() behaviors) would require a new keyword-only flag to gather(). If we're going to deemphasize it I might not bother though.

      There's one thing that gather() does that TaskGroup doesn't: it gives us the return values from the tasks. The question is whether that's useful. If it is maybe we should *not* deepmhasize gather() quite as much and then adding new features would be okay.

    11. gvanrossum commented on Feb 16, 2022

      @gvanrossum
      gvanrossum
      on Feb 16, 2022
      MemberAuthor
      More actions

      I've created a separate issue for cancel scopes: bpo-46771.

    12. 1st1 commented on Feb 16, 2022

      @1st1
      1st1
      on Feb 16, 2022
      Member
      More actions

      There's one thing that gather() does that TaskGroup doesn't: it gives us the return values from the tasks.

      That's easy to do with task groups too:

        async with TaskGroup() as g:
            r1 = g.create_task(coro1())
            r2 = g.create_task(coro2())
      
        print(r1.result())
      
        # or
        print(await r2)  # I *think* this should work
      Reacted by Giorgi
      Reacted by Giorgi
    13. gvanrossum commented on Feb 16, 2022

      @gvanrossum
      gvanrossum
      on Feb 16, 2022
      MemberAuthor
      More actions

      I have a PR up to typeshed to add the new Task methods and a new stub file taskgroups.pyi: python/typeshed#7240

    14. gvanrossum commented on Feb 18, 2022

      @gvanrossum
      gvanrossum
      on Feb 18, 2022
      MemberAuthor
      More actions

      New changeset d851216 by Guido van Rossum in branch 'main':
      bpo-46752: Slight improvements to TaskGroup API (GH-31398)
      d851216

    15. 11 remaining items

    16. ezio-melotti
      added this to Release and Deferred blockers 🚫on Jun 30, 2022
    17. ambv
      added a commit that references this issue on Jun 30, 2022

      GH-90908: Document asyncio.TaskGroup (GH-94359)

      b6ec6d4
    18. miss-islington
      added a commit that references this issue on Jun 30, 2022

      pythonGH-90908: Document asyncio.TaskGroup (pythonGH-94359)

      72ed089
    19. ambv
      added a commit that references this issue on Jun 30, 2022

      GH-90908: Document asyncio.TaskGroup (GH-94359) (GH-94456)

      b3d69ff
    20. gvanrossum commented on Jun 30, 2022

      @gvanrossum
      gvanrossum
      on Jun 30, 2022
      MemberAuthor
      More actions

      Now the docs are up we can close this.

      Reacted by Or Chen
    21. gvanrossum
      closed this as completedon Jun 30, 2022
    22. gvanrossum
      moved this to Done in asyncioon Jun 30, 2022
    23. gvanrossum
      added a commit that references this issue on Jun 30, 2022

      pythonGH-90908: Document asyncio.TaskGroup (pythonGH-94359)

      159a057
    24. ambv
      added a commit that references this issue on Jul 25, 2022

      pythongh-90908: Document asyncio.Task.cancelling() and asyncio.Task.u…

      708cb27
    25. gvanrossum
      added a commit that references this issue on Oct 1, 2022

      gh-90908: Document asyncio.Task.cancelling() and asyncio.Task.uncance…

      f00645d
    26. miss-islington
      added 2 commits that reference this issue on Oct 1, 2022

      pythongh-90908: Document asyncio.Task.cancelling() and asyncio.Task.u…

      da10989

      gh-90908: Document asyncio.Task.cancelling() and asyncio.Task.uncance…

      3614bbb
    27. serhiy-storchaka
      added a commit that references this issue on Oct 2, 2022

      pythongh-90908: Document asyncio.Task.cancelling() and asyncio.Task.u…

      fb39e7f
    28. pablogsal
      added a commit that references this issue on Oct 24, 2022

      gh-90908: Document asyncio.Task.cancelling() and asyncio.Task.uncance…

      f008392
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    • @gvanrossum
      gvanrossum

    Labels

    3.11only security fixesonly security fixesdeferred-blockertopic-asyncio

    Projects

    • Release and Deferred blockers 🚫
      Status
      No status
      Show more project fields
    • asyncio
      Status
      Done
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.