Skip to content

Commit 49b236e

Browse files
committed
gh-155502: Warn about keeping a reference to tasks from loop.create_task
The low-level Event Loop documentation for create_task() did not repeat the warning from the high-level asyncio.create_task() docs that the event loop only keeps weak references to tasks, so a task that is not referenced elsewhere may be garbage collected before it completes. Mirror the note (including the fire-and-forget collection pattern) in the loop.create_task() documentation.
1 parent ee68f5f commit 49b236e

1 file changed

Lines changed: 33 additions & 0 deletions

File tree

Doc/library/asyncio-eventloop.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,39 @@ Creating futures and tasks
388388
or be scheduled later. If *eager_start* is not passed the mode set
389389
by :meth:`loop.set_task_factory` will be used.
390390

391+
.. important::
392+
393+
Save a reference to the result of this function, to avoid
394+
a task disappearing mid-execution. The event loop only keeps
395+
weak references to tasks. A task that isn't referenced elsewhere
396+
may get garbage collected at any time, even before it's done.
397+
For reliable "fire-and-forget" background tasks, gather them in
398+
a collection::
399+
400+
background_tasks = set()
401+
402+
for i in range(10):
403+
task = loop.create_task(some_coro(param=i))
404+
405+
# Add task to the set. This creates a strong reference.
406+
background_tasks.add(task)
407+
408+
# To prevent keeping references to finished tasks forever,
409+
# make each task remove its own reference from the set after
410+
# completion:
411+
task.add_done_callback(background_tasks.discard)
412+
413+
Note that this approach never awaits the tasks, so if a task
414+
fails, its exception is never retrieved and asyncio logs a
415+
"Task exception was never retrieved" message when the task is
416+
garbage collected. To avoid this, use :class:`asyncio.TaskGroup`
417+
which keeps a strong reference to each task, awaits them and
418+
propagates their exceptions::
419+
420+
async with asyncio.TaskGroup() as tg:
421+
for i in range(10):
422+
tg.create_task(some_coro(param=i))
423+
391424
.. versionchanged:: 3.8
392425
Added the *name* parameter.
393426

0 commit comments

Comments
 (0)