Repository navigation
asyncio.create_task() documentation should mention user needs to keep reference to the task #88831
Description
Activity
vincentbernat commented
on Jul 18, 2021 vincentbernatmannequinMannequinAuthorMore actionsasyncio 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()".
- added3.9 (EOL)end of lifeend of life3.10 (EOL)end of lifeend of life3.11only security fixesonly security fixes
on Jul 18, 2021 - addeddocsDocumentation in the Doc dirDocumentation in the Doc dir3.9 (EOL)end of lifeend of lifetype-featureA feature request or enhancementA feature request or enhancement3.10 (EOL)end of lifeend of life3.11only security fixesonly security fixes
on Jul 18, 2021 - addeddocsDocumentation in the Doc dirDocumentation in the Doc dirtype-featureA feature request or enhancementA feature request or enhancement
on Jul 18, 2021 @bernat and ncoghlan, please see if the wording I have used in the linked PR helps to clarify this.
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()
22 remaining items
- added 2 commits that reference this issue
on Feb 13, 2023 - added 2 commits that reference this issue
on Jul 17, 2023 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:
- added a commit that references this issue
on Aug 17, 2023 - added a commit that references this issue
on Sep 12, 2023 - added a commit that references this issue
on Oct 14, 2023 @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.
Only the last one will work. The two other ones don't keep a reference on the tasks after the coro() function ends.
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
awaitinside 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 directlyaway 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.
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).
- added a commit that references this issue
on May 2, 2024 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- added a commit that references this issue
on Aug 31, 2026
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:
bugs.python.org fields: