bpo-31970: Reduce performance overhead of asyncio debug mode. (#4314)
* bpo-31970: Reduce performance overhead of asyncio debug mode.
This commit is contained in:
parent
1e5d54cfa0
commit
921e9432a1
@ -1223,6 +1223,11 @@ class BaseEventLoop(events.AbstractEventLoop):
|
|||||||
handler is set, and can be called by a custom exception
|
handler is set, and can be called by a custom exception
|
||||||
handler that wants to defer to the default behavior.
|
handler that wants to defer to the default behavior.
|
||||||
|
|
||||||
|
This default handler logs the error message and other
|
||||||
|
context-dependent information. In debug mode, a truncated
|
||||||
|
stack trace is also appended showing where the given object
|
||||||
|
(e.g. a handle or future or task) was created, if any.
|
||||||
|
|
||||||
The context parameter has the same meaning as in
|
The context parameter has the same meaning as in
|
||||||
`call_exception_handler()`.
|
`call_exception_handler()`.
|
||||||
"""
|
"""
|
||||||
|
@ -5,3 +5,8 @@ LOG_THRESHOLD_FOR_CONNLOST_WRITES = 5
|
|||||||
|
|
||||||
# Seconds to wait before retrying accept().
|
# Seconds to wait before retrying accept().
|
||||||
ACCEPT_RETRY_DELAY = 1
|
ACCEPT_RETRY_DELAY = 1
|
||||||
|
|
||||||
|
# Number of stack entries to capture in debug mode.
|
||||||
|
# The large the number, the slower the operation in debug mode
|
||||||
|
# (see extract_stack() in events.py)
|
||||||
|
DEBUG_STACK_DEPTH = 10
|
||||||
|
@ -10,6 +10,7 @@ import traceback
|
|||||||
import types
|
import types
|
||||||
|
|
||||||
from . import compat
|
from . import compat
|
||||||
|
from . import constants
|
||||||
from . import events
|
from . import events
|
||||||
from . import base_futures
|
from . import base_futures
|
||||||
from .log import logger
|
from .log import logger
|
||||||
@ -91,7 +92,7 @@ class CoroWrapper:
|
|||||||
assert inspect.isgenerator(gen) or inspect.iscoroutine(gen), gen
|
assert inspect.isgenerator(gen) or inspect.iscoroutine(gen), gen
|
||||||
self.gen = gen
|
self.gen = gen
|
||||||
self.func = func # Used to unwrap @coroutine decorator
|
self.func = func # Used to unwrap @coroutine decorator
|
||||||
self._source_traceback = traceback.extract_stack(sys._getframe(1))
|
self._source_traceback = events.extract_stack(sys._getframe(1))
|
||||||
self.__name__ = getattr(gen, '__name__', None)
|
self.__name__ = getattr(gen, '__name__', None)
|
||||||
self.__qualname__ = getattr(gen, '__qualname__', None)
|
self.__qualname__ = getattr(gen, '__qualname__', None)
|
||||||
|
|
||||||
@ -183,8 +184,9 @@ class CoroWrapper:
|
|||||||
tb = getattr(self, '_source_traceback', ())
|
tb = getattr(self, '_source_traceback', ())
|
||||||
if tb:
|
if tb:
|
||||||
tb = ''.join(traceback.format_list(tb))
|
tb = ''.join(traceback.format_list(tb))
|
||||||
msg += ('\nCoroutine object created at '
|
msg += (f'\nCoroutine object created at '
|
||||||
'(most recent call last):\n')
|
f'(most recent call last, truncated to '
|
||||||
|
f'{constants.DEBUG_STACK_DEPTH} last lines):\n')
|
||||||
msg += tb.rstrip()
|
msg += tb.rstrip()
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ import sys
|
|||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
from . import constants
|
||||||
|
|
||||||
|
|
||||||
def _get_function_source(func):
|
def _get_function_source(func):
|
||||||
func = inspect.unwrap(func)
|
func = inspect.unwrap(func)
|
||||||
@ -72,6 +74,23 @@ def _format_callback_source(func, args):
|
|||||||
return func_repr
|
return func_repr
|
||||||
|
|
||||||
|
|
||||||
|
def extract_stack(f=None, limit=None):
|
||||||
|
"""Replacement for traceback.extract_stack() that only does the
|
||||||
|
necessary work for asyncio debug mode.
|
||||||
|
"""
|
||||||
|
if f is None:
|
||||||
|
f = sys._getframe().f_back
|
||||||
|
if limit is None:
|
||||||
|
# Limit the amount of work to a reasonable amount, as extract_stack()
|
||||||
|
# can be called for each coroutine and future in debug mode.
|
||||||
|
limit = constants.DEBUG_STACK_DEPTH
|
||||||
|
stack = traceback.StackSummary.extract(traceback.walk_stack(f),
|
||||||
|
limit=limit,
|
||||||
|
lookup_lines=False)
|
||||||
|
stack.reverse()
|
||||||
|
return stack
|
||||||
|
|
||||||
|
|
||||||
class Handle:
|
class Handle:
|
||||||
"""Object returned by callback registration methods."""
|
"""Object returned by callback registration methods."""
|
||||||
|
|
||||||
@ -85,7 +104,7 @@ class Handle:
|
|||||||
self._cancelled = False
|
self._cancelled = False
|
||||||
self._repr = None
|
self._repr = None
|
||||||
if self._loop.get_debug():
|
if self._loop.get_debug():
|
||||||
self._source_traceback = traceback.extract_stack(sys._getframe(1))
|
self._source_traceback = extract_stack(sys._getframe(1))
|
||||||
else:
|
else:
|
||||||
self._source_traceback = None
|
self._source_traceback = None
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ class Future:
|
|||||||
self._loop = loop
|
self._loop = loop
|
||||||
self._callbacks = []
|
self._callbacks = []
|
||||||
if self._loop.get_debug():
|
if self._loop.get_debug():
|
||||||
self._source_traceback = traceback.extract_stack(sys._getframe(1))
|
self._source_traceback = events.extract_stack(sys._getframe(1))
|
||||||
|
|
||||||
_repr_info = base_futures._future_repr_info
|
_repr_info = base_futures._future_repr_info
|
||||||
|
|
||||||
|
@ -1981,7 +1981,7 @@ class BaseTaskTests:
|
|||||||
|
|
||||||
regex = (r'^<CoroWrapper %s\(?\)? .* at %s:%s, .*> '
|
regex = (r'^<CoroWrapper %s\(?\)? .* at %s:%s, .*> '
|
||||||
r'was never yielded from\n'
|
r'was never yielded from\n'
|
||||||
r'Coroutine object created at \(most recent call last\):\n'
|
r'Coroutine object created at \(most recent call last, truncated to \d+ last lines\):\n'
|
||||||
r'.*\n'
|
r'.*\n'
|
||||||
r' File "%s", line %s, in test_coroutine_never_yielded\n'
|
r' File "%s", line %s, in test_coroutine_never_yielded\n'
|
||||||
r' coro_noop\(\)$'
|
r' coro_noop\(\)$'
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
Reduce performance overhead of asyncio debug mode.
|
Loading…
x
Reference in New Issue
Block a user