mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
bpo-34037: Fix test_asyncio failure and add loop.shutdown_default_executor() (GH-15735)
This commit is contained in:
parent
3171d67a6a
commit
9fdc64cf12
6 changed files with 54 additions and 2 deletions
|
@ -406,6 +406,8 @@ class BaseEventLoop(events.AbstractEventLoop):
|
|||
self._asyncgens = weakref.WeakSet()
|
||||
# Set to True when `loop.shutdown_asyncgens` is called.
|
||||
self._asyncgens_shutdown_called = False
|
||||
# Set to True when `loop.shutdown_default_executor` is called.
|
||||
self._executor_shutdown_called = False
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
|
@ -503,6 +505,10 @@ class BaseEventLoop(events.AbstractEventLoop):
|
|||
if self._closed:
|
||||
raise RuntimeError('Event loop is closed')
|
||||
|
||||
def _check_default_executor(self):
|
||||
if self._executor_shutdown_called:
|
||||
raise RuntimeError('Executor shutdown has been called')
|
||||
|
||||
def _asyncgen_finalizer_hook(self, agen):
|
||||
self._asyncgens.discard(agen)
|
||||
if not self.is_closed():
|
||||
|
@ -543,6 +549,26 @@ class BaseEventLoop(events.AbstractEventLoop):
|
|||
'asyncgen': agen
|
||||
})
|
||||
|
||||
async def shutdown_default_executor(self):
|
||||
"""Schedule the shutdown of the default executor."""
|
||||
self._executor_shutdown_called = True
|
||||
if self._default_executor is None:
|
||||
return
|
||||
future = self.create_future()
|
||||
thread = threading.Thread(target=self._do_shutdown, args=(future,))
|
||||
thread.start()
|
||||
try:
|
||||
await future
|
||||
finally:
|
||||
thread.join()
|
||||
|
||||
def _do_shutdown(self, future):
|
||||
try:
|
||||
self._default_executor.shutdown(wait=True)
|
||||
self.call_soon_threadsafe(future.set_result, None)
|
||||
except Exception as ex:
|
||||
self.call_soon_threadsafe(future.set_exception, ex)
|
||||
|
||||
def run_forever(self):
|
||||
"""Run until stop() is called."""
|
||||
self._check_closed()
|
||||
|
@ -632,6 +658,7 @@ class BaseEventLoop(events.AbstractEventLoop):
|
|||
self._closed = True
|
||||
self._ready.clear()
|
||||
self._scheduled.clear()
|
||||
self._executor_shutdown_called = True
|
||||
executor = self._default_executor
|
||||
if executor is not None:
|
||||
self._default_executor = None
|
||||
|
@ -768,6 +795,8 @@ class BaseEventLoop(events.AbstractEventLoop):
|
|||
self._check_callback(func, 'run_in_executor')
|
||||
if executor is None:
|
||||
executor = self._default_executor
|
||||
# Only check when the default executor is being used
|
||||
self._check_default_executor()
|
||||
if executor is None:
|
||||
executor = concurrent.futures.ThreadPoolExecutor()
|
||||
self._default_executor = executor
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue