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 — asyncio.create_task() documentation should mention user needs to keep reference to the task · Issue #88831 · python/cpython

asyncio.create_task() documentation should mention user needs to keep reference to the task #88831

New issue
Copy link
New issue
Copy link
Closed
Closed
asyncio.create_task() documentation should mention user needs to keep reference to the task#88831
Copy link
Labels
3.10 (EOL)end of lifeend of life3.11only security fixesonly security fixesdocsDocumentation in the Doc dirDocumentation in the Doc dirtype-featureA feature request or enhancementA feature request or enhancement

Description

vincentbernat
mannequin
opened on Jul 18, 2021
Issue body actions
BPO 44665
Nosy @cmeyer, @nanjekyejoannah, @vincentbernat, @alexhartl
PRs
  • bpo-44665: asyncio.create_task() documentation should mention user needs to keep reference to the task #29163
  • 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 = None
    closed_at = None
    created_at = <Date 2021-07-18.06:01:26.261>
    labels = ['3.11', 'type-feature', '3.9', '3.10', 'docs']
    title = 'asyncio.create_task() documentation should mention user needs to keep reference to the task'
    updated_at = <Date 2022-01-06.08:53:46.602>
    user = 'https://github.com/vincentbernat'

    bugs.python.org fields:

    activity = <Date 2022-01-06.08:53:46.602>
    actor = 'alexhartl'
    assignee = 'docs@python'
    closed = False
    closed_date = None
    closer = None
    components = ['Documentation']
    creation = <Date 2021-07-18.06:01:26.261>
    creator = 'bernat'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 44665
    keywords = ['patch']
    message_count = 5.0
    messages = ['397741', '404776', '404782', '404827', '409821']
    nosy_count = 5.0
    nosy_names = ['docs@python', 'cmeyer', 'nanjekyejoannah', 'bernat', 'alexhartl']
    pr_nums = ['29163']
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue44665'
    versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']

    Activity

    Next
    1. vincentbernat commented on Jul 18, 2021

      @vincentbernat
      vincentbernatmannequin
      on Jul 18, 2021
      MannequinAuthor
      More actions

      asyncio will only keep weak references to alive tasks (in _all_tasks). If a user does not keep a reference to a task and the task is not currently executing or sleeping, the user may get "Task was destroyed but it is pending!".

      I would suggest adding the following paragraph to create_task() documentation:

      Python only keeps weak references to the scheduled tasks. To avoid the task being destroyed by the garbage collector while still pending, a reference to it should be kept until the task is done.

      And maybe an example in case a user wants something "fire and forget"?

      running_tasks = set()
      # [...]
      task = asyncio.create_task(some_background_function())
      running_tasks.add(task)
      task.add_done_callback(lambda t: running_tasks.remove(t))

      The same applies to ensure_future as it now uses create_task, so maybe a "See create_task()".

    2. vincentbernat
      added
      3.9 (EOL)end of lifeend of life
      3.10 (EOL)end of lifeend of life
      3.11only security fixesonly security fixes
      on Jul 18, 2021
    3. vincentbernat
      assigned
      docspython
      on Jul 18, 2021
    4. vincentbernat
      added
      docsDocumentation in the Doc dirDocumentation in the Doc dir
      3.9 (EOL)end of lifeend of life
      type-featureA feature request or enhancementA feature request or enhancement
      3.10 (EOL)end of lifeend of life
      3.11only security fixesonly security fixes
      on Jul 18, 2021
    5. vincentbernat
      assigned
      docspython
      on Jul 18, 2021
    6. vincentbernat
      added
      docsDocumentation in the Doc dirDocumentation in the Doc dir
      type-featureA feature request or enhancementA feature request or enhancement
      on Jul 18, 2021
    7. nanjekyejoannah commented on Oct 22, 2021

      @nanjekyejoannah
      nanjekyejoannah
      on Oct 22, 2021
      Contributor
      More actions

      @bernat and ncoghlan, please see if the wording I have used in the linked PR helps to clarify this.

    8. cmeyer commented on Oct 22, 2021

      @cmeyer
      cmeyermannequin
      on Oct 22, 2021
      Mannequin
      More actions

      Is there a way to reproduce this issue? I run the following code in Python 3.9 and it works as expected (prints "xyz" twice).

      import asyncio
      import gc
      
      async def xyz():
          print("xyz")
      
      event_loop = asyncio.get_event_loop()
      
      event_loop.create_task(xyz())
      
      t = event_loop.create_task(xyz())
      del t
      
      gc.collect()
      
      event_loop.stop()
      event_loop.run_forever()
    9. 22 remaining items

    10. bdraco
      added 2 commits that reference this issue on Feb 13, 2023

      Ensure we hold strong references to tasks

      6449a47

      Ensure we hold strong references to tasks

      0d5019c
    11. SomberNight
      added 2 commits that reference this issue on Jul 17, 2023

      util.CallbackManager: keep strong references for running futures

      ab05374

      util.CallbackManager: keep strong references for running futures

      6977be8
    12. amirsoroush commented on Aug 5, 2023

      @amirsoroush
      amirsoroush
      on Aug 5, 2023
      More actions

      Is there a way to reproduce this issue? I run the following code in Python 3.9 and it works as expected (prints "xyz" twice).

      import asyncio
      import gc
      
      async def xyz():
          print("xyz")
      
      event_loop = asyncio.get_event_loop()
      
      event_loop.create_task(xyz())
      
      t = event_loop.create_task(xyz())
      del t
      
      gc.collect()
      
      event_loop.stop()
      event_loop.run_forever()

      Here is my answer for anyone wondering how to reproduce this issue (as their code works just fine without keeping a reference to the tasks). I tried to explain what I understood:

      https://stackoverflow.com/a/76823668/13944524

    13. SomberNight
      added a commit that references this issue on Aug 17, 2023

      util.CallbackManager: keep strong references for running futures

      ebc4a00
    14. SomberNight
      added a commit that references this issue on Sep 12, 2023

      util.CallbackManager: keep strong references for running futures

      efff1ce
    15. sha-265
      added a commit that references this issue on Oct 14, 2023

      util.CallbackManager: keep strong references for running futures

      32f778a
    16. ggregoire commented on Feb 28, 2024

      @ggregoire
      ggregoire
      on Feb 28, 2024
      More actions

      @vincentbernat just to clarify, since I'm not that familiar with the intricacies of Python's garbage collector.

      Is this enough (in the context of this issue) to keep a reference of the task like this?

      async def coro():
          task1 = asyncio.create_task(...)
          task2 = asyncio.create_task(...)
          task3 = asyncio.create_task(...)
          task4 = asyncio.create_task(...)

      Or is it really needed to keep them in a collection?

      If so, can the collection be declared inside the coroutine? Or does it need to be outside to be a "strong" reference?

      async def coro():
          running_tasks = set()
          task1 = asyncio.create_task(...)
          running_tasks.add(task1)
          task2 = asyncio.create_task(...)
          running_tasks.add(task2)
          task3 = asyncio.create_task(...)
          running_tasks.add(task3)
          task4 = asyncio.create_task(...)
          running_tasks.add(task4)

      vs.

      running_tasks = set()
      
      async def coro():
          task1 = asyncio.create_task(...)
          running_tasks.add(task1)
          task2 = asyncio.create_task(...)
          running_tasks.add(task2)
          task3 = asyncio.create_task(...)
          running_tasks.add(task3)
          task4 = asyncio.create_task(...)
          running_tasks.add(task4)

      Just trying to keep the code as simple as possible.

    17. vincentbernat commented on Feb 28, 2024

      @vincentbernat
      vincentbernat
      on Feb 28, 2024
      ContributorAuthor
      More actions

      Only the last one will work. The two other ones don't keep a reference on the tasks after the coro() function ends.

    18. ggregoire commented on Feb 28, 2024

      @ggregoire
      ggregoire
      on Feb 28, 2024
      More actions

      Only the last one will work. The two other ones don't keep a reference on the tasks after the coro() function ends.

      But when the coro() function ends, all the tasks created inside coro() are done, so I don't need to keep the references anymore, right?

      Maybe I should have clarified that I call the await inside the same coro() function.

      So like:

      async def coro():
          task1 = asyncio.create_task(...)
          task2 = asyncio.create_task(...)
          task3 = asyncio.create_task(...)
          task4 = asyncio.create_task(...)
          await task1
          await task2
          await task3
          await task4
          # all the tasks are done and coro() ends

      In this case, would it work? Do I even need to keep the references task1, task2, etc or can I do directly away asyncio.create_task(...) without risking my tasks to be garbage collected before they are done?

      async def coro():
          await asyncio.create_task(...)
          await asyncio.create_task(...)
          await asyncio.create_task(...)
          await asyncio.create_task(...)
          # all the tasks are done and coro() ends

      Thanks for the help.


      Editing this post to avoid creating more noise:

      I don't think this issue should be a support forum.

      Agree but the documentation was updated following this issue and the wording is confusing. As you can see in the previous comments and in mine, it raises a lot of questions. The doc suggests to keep references of the tasks in any case, while apparently is not always necessary (like in my example).

      I appreciate the help anyway. Thanks.

    19. vincentbernat commented on Feb 28, 2024

      @vincentbernat
      vincentbernat
      on Feb 28, 2024
      ContributorAuthor
      More actions

      I don't think this issue should be a support forum. But yes, both ways are fine (but they don't do the same thing).

    20. Atry
      added a commit that references this issue on May 2, 2024

      [BugFix] Prevent the task of `_force_log` from being garbage collected

      9043f78
    21. pkch commented on Oct 20, 2024

      @pkch
      pkch
      on Oct 20, 2024
      More actions

      Is there any reason why the event loop should not keep strong reference to the task until the task is completed?
      -- never mind, this is being discussed already here: #91887

    22. TheButterZone
      added a commit that references this issue on Aug 31, 2026

      util.CallbackManager: keep strong references for running futures

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

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.10 (EOL)end of lifeend of life3.11only security fixesonly security fixesdocsDocumentation in the Doc dirDocumentation in the Doc dirtype-featureA feature request or enhancementA feature request or enhancement

      Projects

      No projects

        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.