未验证 提交 b5dad636 编写于 作者: B Ben Darnell 提交者: GitHub

Merge pull request #3269 from bdarnell/refer-to-all-tasks

gen: Hold strong references to all asyncio.Tasks
......@@ -840,13 +840,17 @@ class Runner(object):
return False
# Convert Awaitables into Futures.
try:
_wrap_awaitable = asyncio.ensure_future
except AttributeError:
# asyncio.ensure_future was introduced in Python 3.4.4, but
# Debian jessie still ships with 3.4.2 so try the old name.
_wrap_awaitable = getattr(asyncio, "async")
def _wrap_awaitable(awaitable: Awaitable) -> Future:
# Convert Awaitables into Futures.
# Note that we use ensure_future, which handles both awaitables
# and coroutines, rather than create_task, which only accepts
# coroutines. (ensure_future calls create_task if given a coroutine)
fut = asyncio.ensure_future(awaitable)
# See comments on IOLoop._pending_tasks.
loop = IOLoop.current()
loop._register_task(fut)
fut.add_done_callback(lambda f: loop._unregister_task(f))
return fut
def convert_yielded(yielded: _Yieldable) -> Future:
......
......@@ -50,7 +50,7 @@ import typing
from typing import Union, Any, Type, Optional, Callable, TypeVar, Tuple, Awaitable
if typing.TYPE_CHECKING:
from typing import Dict, List # noqa: F401
from typing import Dict, List, Set # noqa: F401
from typing_extensions import Protocol
else:
......@@ -159,6 +159,18 @@ class IOLoop(Configurable):
# In Python 3, _ioloop_for_asyncio maps from asyncio loops to IOLoops.
_ioloop_for_asyncio = dict() # type: Dict[asyncio.AbstractEventLoop, IOLoop]
# Maintain a set of all pending tasks to follow the warning in the docs
# of asyncio.create_tasks:
# https://docs.python.org/3.11/library/asyncio-task.html#asyncio.create_task
# This ensures that all pending tasks have a strong reference so they
# will not be garbage collected before they are finished.
# (Thus avoiding "task was destroyed but it is pending" warnings)
# An analogous change has been proposed in cpython for 3.13:
# https://github.com/python/cpython/issues/91887
# If that change is accepted, this can eventually be removed.
# If it is not, we will consider the rationale and may remove this.
_pending_tasks = set() # type: Set[Future]
@classmethod
def configure(
cls, impl: "Union[None, str, Type[Configurable]]", **kwargs: Any
......@@ -805,6 +817,12 @@ class IOLoop(Configurable):
except OSError:
pass
def _register_task(self, f: Future) -> None:
self._pending_tasks.add(f)
def _unregister_task(self, f: Future) -> None:
self._pending_tasks.discard(f)
class _Timeout(object):
"""An IOLoop timeout, a UNIX timestamp and a callback"""
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册