From 6ed9465e909efab02095e73d60a07f4cbe3b0aaf Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 10:53:43 -0400 Subject: [PATCH 01/26] Add flag BaseEventLoop._executor_shutdown_called --- Lib/asyncio/base_events.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 14b80bdda9c039..aa666292df3800 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -404,8 +404,11 @@ def __init__(self): # A weak set of all asynchronous generators that are # being iterated by the loop. 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 ( From 8608e97fac0a894de13a05feca39b5bcf714db16 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 10:59:38 -0400 Subject: [PATCH 02/26] Add abstract method for loop.shutdown_default_executor() --- Lib/asyncio/events.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index 5fb546429cbee5..58c22cff6b17fa 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -249,6 +249,12 @@ async def shutdown_asyncgens(self): """Shutdown all active asynchronous generators.""" raise NotImplementedError + def shutdown_default_executor(self): + """Shutdown the default executor and wait for the threads + in the threadpool to finish joining. + """ + raise NotImplementedError + # Methods scheduling callbacks. All these return Handles. def _timer_handle_cancelled(self, handle): From 7f39c4acea0d073b48c6defff81ae3ded6c1d54f Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 11:11:50 -0400 Subject: [PATCH 03/26] Add BaseEventLoop method shutdown_default_executor() --- Lib/asyncio/base_events.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index aa666292df3800..1f65ba14a0c24c 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -546,6 +546,16 @@ async def shutdown_asyncgens(self): 'asyncgen': agen }) + def shutdown_default_executor(self): + """Shutdown the default executor, but wait for the threads + in the threadpool to finish joining. + """ + self._executor_shutdown_called = True + executor = self._default_executor + if executor is not None: + self._default_executor = None + executor.shutdown(wait=True) + def run_forever(self): """Run until stop() is called.""" self._check_closed() From 09a94588af5f27a818135d1f9bde0640862a5be8 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 11:13:05 -0400 Subject: [PATCH 04/26] Remove whitespace --- Lib/asyncio/base_events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 1f65ba14a0c24c..a4275875ad1efe 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -554,7 +554,7 @@ def shutdown_default_executor(self): executor = self._default_executor if executor is not None: self._default_executor = None - executor.shutdown(wait=True) + executor.shutdown(wait=True) def run_forever(self): """Run until stop() is called.""" From c12cf4ff387ca057dcd29ca023783e00fa0fe059 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 11:22:39 -0400 Subject: [PATCH 05/26] Add BaseEventLoop internal method _check_executor_shutdown() --- Lib/asyncio/base_events.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index a4275875ad1efe..715b755e2b8d35 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -506,6 +506,10 @@ def _check_closed(self): if self._closed: raise RuntimeError('Event loop is closed') + def _check_executor_shutdown(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(): From afa09a5d590c5ff397a4c25bb36885b7806158fa Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 11:27:20 -0400 Subject: [PATCH 06/26] Adjust docstring for abstract method loop.shutdown_default_executor --- Lib/asyncio/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index 58c22cff6b17fa..157360bf7bbba3 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -250,7 +250,7 @@ async def shutdown_asyncgens(self): raise NotImplementedError def shutdown_default_executor(self): - """Shutdown the default executor and wait for the threads + """Shutdown the default executor, but wait for the threads in the threadpool to finish joining. """ raise NotImplementedError From 3303753b77c7b8868446070331323170a311ccd8 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 11:40:01 -0400 Subject: [PATCH 07/26] Rename method _check_executor_shutdown() to _check_default_executor() --- Lib/asyncio/base_events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 715b755e2b8d35..e549cd62fea4ed 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -506,7 +506,7 @@ def _check_closed(self): if self._closed: raise RuntimeError('Event loop is closed') - def _check_executor_shutdown(self): + def _check_default_executor(self): if self._executor_shutdown_called: raise RuntimeError('Executor shutdown has been called') From b877e76bc77bb2196f7b480fcd917703553e3d1b Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 11:43:49 -0400 Subject: [PATCH 08/26] Add default executor check to loop.run_in_executor() --- Lib/asyncio/base_events.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index e549cd62fea4ed..97ea3217e7485f 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -785,6 +785,8 @@ def run_in_executor(self, executor, func, *args): 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 From 1a29d83b21014b39714a10a8f565b2e31072a3fa Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 11:49:01 -0400 Subject: [PATCH 09/26] Implement loop.shutdown_default_executors() in asyncio.run() --- Lib/asyncio/runners.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/asyncio/runners.py b/Lib/asyncio/runners.py index 5fbab03dd001ac..16132af93500f6 100644 --- a/Lib/asyncio/runners.py +++ b/Lib/asyncio/runners.py @@ -45,6 +45,7 @@ async def main(): try: _cancel_all_tasks(loop) loop.run_until_complete(loop.shutdown_asyncgens()) + loop.shutdown_default_executor() finally: events.set_event_loop(None) loop.close() From 6bde87c5f493b4878c3504755b9050f30c920da2 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 12:53:12 -0400 Subject: [PATCH 10/26] Remove empty line --- Lib/asyncio/base_events.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 97ea3217e7485f..cb25370ba374c1 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -404,7 +404,6 @@ def __init__(self): # A weak set of all asynchronous generators that are # being iterated by the loop. 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. From 1e4a858a73544742f6d96910ff5cb2a0e255a649 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 13:20:22 -0400 Subject: [PATCH 11/26] Shorten `loop.shutdown_default_executor()` docstring --- Lib/asyncio/base_events.py | 4 +--- Lib/asyncio/events.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index cb25370ba374c1..299b8f237873a7 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -550,9 +550,7 @@ async def shutdown_asyncgens(self): }) def shutdown_default_executor(self): - """Shutdown the default executor, but wait for the threads - in the threadpool to finish joining. - """ + """Shutdown the default executor, but wait for the threadpool to finish.""" self._executor_shutdown_called = True executor = self._default_executor if executor is not None: diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index 157360bf7bbba3..4ac50248b4d4f8 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -250,9 +250,7 @@ async def shutdown_asyncgens(self): raise NotImplementedError def shutdown_default_executor(self): - """Shutdown the default executor, but wait for the threads - in the threadpool to finish joining. - """ + """Shutdown the default executor, but wait for the threadpool to finish.""" raise NotImplementedError # Methods scheduling callbacks. All these return Handles. From 8a4a285c6b6ca3682d93666c9fbb1b3bf17d1f8b Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 13:30:53 -0400 Subject: [PATCH 12/26] Add _shutdown_default_executor() to reduce duplicate code --- Lib/asyncio/base_events.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 299b8f237873a7..90c62e273265cc 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -549,13 +549,17 @@ async def shutdown_asyncgens(self): 'asyncgen': agen }) - def shutdown_default_executor(self): - """Shutdown the default executor, but wait for the threadpool to finish.""" + + def _shutdown_default_executor(self, wait=True): self._executor_shutdown_called = True executor = self._default_executor if executor is not None: self._default_executor = None - executor.shutdown(wait=True) + executor.shutdown(wait) + + def shutdown_default_executor(self): + """Shutdown the default executor, but wait for the threadpool to finish.""" + self._shutdown_default_executor() def run_forever(self): """Run until stop() is called.""" @@ -646,10 +650,7 @@ def close(self): self._closed = True self._ready.clear() self._scheduled.clear() - executor = self._default_executor - if executor is not None: - self._default_executor = None - executor.shutdown(wait=False) + self._shutdown_default_executor(wait=False) def is_closed(self): """Returns True if the event loop was closed.""" From f6280f7f9978a70abbc3a62f23ffcce87600da64 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 15:15:00 -0400 Subject: [PATCH 13/26] Update documentation --- Doc/library/asyncio-eventloop.rst | 12 ++++++++++++ Doc/library/asyncio-task.rst | 6 ++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 8f7974be66eaa6..e5242160cc41bb 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -166,6 +166,18 @@ Running and stopping the loop loop.close() .. versionadded:: 3.6 + +.. coroutinemethod:: loop.shutdown_default_executor() + + Schedule the closure of the default executor, but wait for the + :class:`ThreadPoolExecutor` to finish joining all of the threads. After + calling this method, a :exc:`RuntimeError` will be raised if + :meth:`loop.run_in_executor` is called while using the default executor. + + Note that there is no need to call this function when + :func:`asyncio.run` is used. + + .. versionadded:: 3.9 Scheduling callbacks diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 1fcdcb985d8842..5ea82db735e753 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -213,8 +213,8 @@ Running an asyncio Program .. function:: run(coro, \*, debug=False) This function runs the passed coroutine, taking care of - managing the asyncio event loop and *finalizing asynchronous - generators*. + managing the asyncio event loop, *finalizing asynchronous + generators*, and closing the threadpool. This function cannot be called when another asyncio event loop is running in the same thread. @@ -229,6 +229,8 @@ Running an asyncio Program **Important:** this function has been added to asyncio in Python 3.7 on a :term:`provisional basis `. + .. versionchanged:: 3.9 + Updated to use :meth:`loop.shutdown_default_executor`. Creating Tasks ============== From 69c72440f41913c8aad04a0e6fb1638c1e0b6ed4 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 15:25:58 -0400 Subject: [PATCH 14/26] Convert `loop.shutdown_default_executor` into a coroutine --- Lib/asyncio/base_events.py | 22 +++++++++++----------- Lib/asyncio/events.py | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 90c62e273265cc..05a5175e069291 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -549,17 +549,13 @@ async def shutdown_asyncgens(self): 'asyncgen': agen }) - - def _shutdown_default_executor(self, wait=True): - self._executor_shutdown_called = True - executor = self._default_executor - if executor is not None: - self._default_executor = None - executor.shutdown(wait) - - def shutdown_default_executor(self): + async def shutdown_default_executor(self): """Shutdown the default executor, but wait for the threadpool to finish.""" - self._shutdown_default_executor() + future = self.create_future() + thread = threading.Thread(target=self._do_shutdown, args=(future,)) + thread.start() + await future + thread.join() def run_forever(self): """Run until stop() is called.""" @@ -650,7 +646,11 @@ def close(self): self._closed = True self._ready.clear() self._scheduled.clear() - self._shutdown_default_executor(wait=False) + self._executor_shutdown_called = True + executor = self._default_executor + if executor is not None: + self._default_executor = None + executor.shutdown(wait=False) def is_closed(self): """Returns True if the event loop was closed.""" diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index 4ac50248b4d4f8..df2453babb2e17 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -249,7 +249,7 @@ async def shutdown_asyncgens(self): """Shutdown all active asynchronous generators.""" raise NotImplementedError - def shutdown_default_executor(self): + async def shutdown_default_executor(self): """Shutdown the default executor, but wait for the threadpool to finish.""" raise NotImplementedError From 76089205f143cb24e201ca83dced9b4c8d9a97e9 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 15:42:28 -0400 Subject: [PATCH 15/26] Add internal method `_do_shutdown()` and fix flag in `shutdown_default_executor() --- Lib/asyncio/base_events.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 05a5175e069291..6d81fb8538e4f2 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -549,8 +549,16 @@ async def shutdown_asyncgens(self): 'asyncgen': agen }) + def _do_shutdown(self, future): + try: + self._executor.shutdown(wait=True) + self.call_soon_threadsafe(future.set_result, None) + except: + self.call_soon_threadsafe(future.set_exception, ex) + async def shutdown_default_executor(self): """Shutdown the default executor, but wait for the threadpool to finish.""" + self._executor_shutdown_called = True future = self.create_future() thread = threading.Thread(target=self._do_shutdown, args=(future,)) thread.start() From 93ddce2b58ad5e768e0ae6ff3990da3fcaeb0dde Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 15:50:31 -0400 Subject: [PATCH 16/26] Update docstrings to reflect changes to `loop.shutdown_default_executor` --- Lib/asyncio/base_events.py | 2 +- Lib/asyncio/events.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 6d81fb8538e4f2..f052a001f0d1b5 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -557,7 +557,7 @@ def _do_shutdown(self, future): self.call_soon_threadsafe(future.set_exception, ex) async def shutdown_default_executor(self): - """Shutdown the default executor, but wait for the threadpool to finish.""" + """Schedule the shutdown of the default executor.""" self._executor_shutdown_called = True future = self.create_future() thread = threading.Thread(target=self._do_shutdown, args=(future,)) diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index df2453babb2e17..2f06c4ae795d2a 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -250,7 +250,7 @@ async def shutdown_asyncgens(self): raise NotImplementedError async def shutdown_default_executor(self): - """Shutdown the default executor, but wait for the threadpool to finish.""" + """Schedule the shutdown of the default executor.""" raise NotImplementedError # Methods scheduling callbacks. All these return Handles. From 895cad071a7a511d5b2829c68a14629e4a879244 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 16:12:04 -0400 Subject: [PATCH 17/26] Misc fixes for `loop._do_shutdown()` --- Lib/asyncio/base_events.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index f052a001f0d1b5..4a7aaf3e2fb1bd 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -549,21 +549,23 @@ async def shutdown_asyncgens(self): 'asyncgen': agen }) - def _do_shutdown(self, future): - try: - self._executor.shutdown(wait=True) - self.call_soon_threadsafe(future.set_result, None) - except: - self.call_soon_threadsafe(future.set_exception, ex) - async def shutdown_default_executor(self): """Schedule the shutdown of the default executor.""" self._executor_shutdown_called = True future = self.create_future() thread = threading.Thread(target=self._do_shutdown, args=(future,)) thread.start() - await future - thread.join() + try: + await future + finally: + thread.join() + + def _do_shutdown(self, future): + try: + self._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.""" From 94e7af41fdf4721f9e6533e9cd8edbfe127cec9d Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 16:14:06 -0400 Subject: [PATCH 18/26] Fix whitespace in `asyncio-eventloop.rst` --- Doc/library/asyncio-eventloop.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index e5242160cc41bb..3823bef9eb87e5 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -166,7 +166,7 @@ Running and stopping the loop loop.close() .. versionadded:: 3.6 - + .. coroutinemethod:: loop.shutdown_default_executor() Schedule the closure of the default executor, but wait for the From 7e4980ce8f26241b6bcc45451466b80e173d1e86 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 16:19:56 -0400 Subject: [PATCH 19/26] Update `asyncio.run()` for `loop.shutdown_default_executor()` coroutine improvement --- Lib/asyncio/runners.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/asyncio/runners.py b/Lib/asyncio/runners.py index 16132af93500f6..6c87747e770bb8 100644 --- a/Lib/asyncio/runners.py +++ b/Lib/asyncio/runners.py @@ -45,7 +45,7 @@ async def main(): try: _cancel_all_tasks(loop) loop.run_until_complete(loop.shutdown_asyncgens()) - loop.shutdown_default_executor() + loop.run_until_complete(loop.shutdown_default_executor()) finally: events.set_event_loop(None) loop.close() From 626117d7b8e81beddb2b72b50bd2ebfb484ead63 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 16:48:27 -0400 Subject: [PATCH 20/26] Fix `loop.shutdown_default_executor()` and whitespace --- Doc/library/asyncio-eventloop.rst | 2 +- Doc/library/asyncio-eventloop.rst.bak | 1675 +++++++++++++++++++++++++ Lib/asyncio/base_events.py | 4 +- 3 files changed, 1679 insertions(+), 2 deletions(-) create mode 100644 Doc/library/asyncio-eventloop.rst.bak diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 3823bef9eb87e5..0bd6bd5bcf9f53 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -166,7 +166,7 @@ Running and stopping the loop loop.close() .. versionadded:: 3.6 - + .. coroutinemethod:: loop.shutdown_default_executor() Schedule the closure of the default executor, but wait for the diff --git a/Doc/library/asyncio-eventloop.rst.bak b/Doc/library/asyncio-eventloop.rst.bak new file mode 100644 index 00000000000000..3823bef9eb87e5 --- /dev/null +++ b/Doc/library/asyncio-eventloop.rst.bak @@ -0,0 +1,1675 @@ +.. currentmodule:: asyncio + + +========== +Event Loop +========== + + +.. rubric:: Preface + +The event loop is the core of every asyncio application. +Event loops run asynchronous tasks and callbacks, perform network +IO operations, and run subprocesses. + +Application developers should typically use the high-level asyncio functions, +such as :func:`asyncio.run`, and should rarely need to reference the loop +object or call its methods. This section is intended mostly for authors +of lower-level code, libraries, and frameworks, who need finer control over +the event loop behavior. + +.. rubric:: Obtaining the Event Loop + +The following low-level functions can be used to get, set, or create +an event loop: + +.. function:: get_running_loop() + + Return the running event loop in the current OS thread. + + If there is no running event loop a :exc:`RuntimeError` is raised. + This function can only be called from a coroutine or a callback. + + .. versionadded:: 3.7 + +.. function:: get_event_loop() + + Get the current event loop. If there is no current event loop set + in the current OS thread and :func:`set_event_loop` has not yet + been called, asyncio will create a new event loop and set it as the + current one. + + Because this function has rather complex behavior (especially + when custom event loop policies are in use), using the + :func:`get_running_loop` function is preferred to :func:`get_event_loop` + in coroutines and callbacks. + + Consider also using the :func:`asyncio.run` function instead of using + lower level functions to manually create and close an event loop. + +.. function:: set_event_loop(loop) + + Set *loop* as a current event loop for the current OS thread. + +.. function:: new_event_loop() + + Create a new event loop object. + +Note that the behaviour of :func:`get_event_loop`, :func:`set_event_loop`, +and :func:`new_event_loop` functions can be altered by +:ref:`setting a custom event loop policy `. + + +.. rubric:: Contents + +This documentation page contains the following sections: + +* The `Event Loop Methods`_ section is the reference documentation of + the event loop APIs; + +* The `Callback Handles`_ section documents the :class:`Handle` and + :class:`TimerHandle` instances which are returned from scheduling + methods such as :meth:`loop.call_soon` and :meth:`loop.call_later`; + +* The `Server Objects`_ section documents types returned from + event loop methods like :meth:`loop.create_server`; + +* The `Event Loop Implementations`_ section documents the + :class:`SelectorEventLoop` and :class:`ProactorEventLoop` classes; + +* The `Examples`_ section showcases how to work with some event + loop APIs. + + +.. _asyncio-event-loop: + +Event Loop Methods +================== + +Event loops have **low-level** APIs for the following: + +.. contents:: + :depth: 1 + :local: + + +Running and stopping the loop +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. method:: loop.run_until_complete(future) + + Run until the *future* (an instance of :class:`Future`) has + completed. + + If the argument is a :ref:`coroutine object ` it + is implicitly scheduled to run as a :class:`asyncio.Task`. + + Return the Future's result or raise its exception. + +.. method:: loop.run_forever() + + Run the event loop until :meth:`stop` is called. + + If :meth:`stop` is called before :meth:`run_forever()` is called, + the loop will poll the I/O selector once with a timeout of zero, + run all callbacks scheduled in response to I/O events (and + those that were already scheduled), and then exit. + + If :meth:`stop` is called while :meth:`run_forever` is running, + the loop will run the current batch of callbacks and then exit. + Note that new callbacks scheduled by callbacks will not run in this + case; instead, they will run the next time :meth:`run_forever` or + :meth:`run_until_complete` is called. + +.. method:: loop.stop() + + Stop the event loop. + +.. method:: loop.is_running() + + Return ``True`` if the event loop is currently running. + +.. method:: loop.is_closed() + + Return ``True`` if the event loop was closed. + +.. method:: loop.close() + + Close the event loop. + + The loop must not be running when this function is called. + Any pending callbacks will be discarded. + + This method clears all queues and shuts down the executor, but does + not wait for the executor to finish. + + This method is idempotent and irreversible. No other methods + should be called after the event loop is closed. + +.. coroutinemethod:: loop.shutdown_asyncgens() + + Schedule all currently open :term:`asynchronous generator` objects to + close with an :meth:`~agen.aclose()` call. After calling this method, + the event loop will issue a warning if a new asynchronous generator + is iterated. This should be used to reliably finalize all scheduled + asynchronous generators. + + Note that there is no need to call this function when + :func:`asyncio.run` is used. + + Example:: + + try: + loop.run_forever() + finally: + loop.run_until_complete(loop.shutdown_asyncgens()) + loop.close() + + .. versionadded:: 3.6 + +.. coroutinemethod:: loop.shutdown_default_executor() + + Schedule the closure of the default executor, but wait for the + :class:`ThreadPoolExecutor` to finish joining all of the threads. After + calling this method, a :exc:`RuntimeError` will be raised if + :meth:`loop.run_in_executor` is called while using the default executor. + + Note that there is no need to call this function when + :func:`asyncio.run` is used. + + .. versionadded:: 3.9 + + +Scheduling callbacks +^^^^^^^^^^^^^^^^^^^^ + +.. method:: loop.call_soon(callback, *args, context=None) + + Schedule a *callback* to be called with *args* arguments at + the next iteration of the event loop. + + Callbacks are called in the order in which they are registered. + Each callback will be called exactly once. + + An optional keyword-only *context* argument allows specifying a + custom :class:`contextvars.Context` for the *callback* to run in. + The current context is used when no *context* is provided. + + An instance of :class:`asyncio.Handle` is returned, which can be + used later to cancel the callback. + + This method is not thread-safe. + +.. method:: loop.call_soon_threadsafe(callback, *args, context=None) + + A thread-safe variant of :meth:`call_soon`. Must be used to + schedule callbacks *from another thread*. + + See the :ref:`concurrency and multithreading ` + section of the documentation. + +.. versionchanged:: 3.7 + The *context* keyword-only parameter was added. See :pep:`567` + for more details. + +.. _asyncio-pass-keywords: + +.. note:: + + Most :mod:`asyncio` scheduling functions don't allow passing + keyword arguments. To do that, use :func:`functools.partial`:: + + # will schedule "print("Hello", flush=True)" + loop.call_soon( + functools.partial(print, "Hello", flush=True)) + + Using partial objects is usually more convenient than using lambdas, + as asyncio can render partial objects better in debug and error + messages. + + +.. _asyncio-delayed-calls: + +Scheduling delayed callbacks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Event loop provides mechanisms to schedule callback functions +to be called at some point in the future. Event loop uses monotonic +clocks to track time. + + +.. method:: loop.call_later(delay, callback, *args, context=None) + + Schedule *callback* to be called after the given *delay* + number of seconds (can be either an int or a float). + + An instance of :class:`asyncio.TimerHandle` is returned which can + be used to cancel the callback. + + *callback* will be called exactly once. If two callbacks are + scheduled for exactly the same time, the order in which they + are called is undefined. + + The optional positional *args* will be passed to the callback when + it is called. If you want the callback to be called with keyword + arguments use :func:`functools.partial`. + + An optional keyword-only *context* argument allows specifying a + custom :class:`contextvars.Context` for the *callback* to run in. + The current context is used when no *context* is provided. + + .. versionchanged:: 3.7 + The *context* keyword-only parameter was added. See :pep:`567` + for more details. + + .. versionchanged:: 3.8 + In Python 3.7 and earlier with the default event loop implementation, + the *delay* could not exceed one day. + This has been fixed in Python 3.8. + +.. method:: loop.call_at(when, callback, *args, context=None) + + Schedule *callback* to be called at the given absolute timestamp + *when* (an int or a float), using the same time reference as + :meth:`loop.time`. + + This method's behavior is the same as :meth:`call_later`. + + An instance of :class:`asyncio.TimerHandle` is returned which can + be used to cancel the callback. + + .. versionchanged:: 3.7 + The *context* keyword-only parameter was added. See :pep:`567` + for more details. + + .. versionchanged:: 3.8 + In Python 3.7 and earlier with the default event loop implementation, + the difference between *when* and the current time could not exceed + one day. This has been fixed in Python 3.8. + +.. method:: loop.time() + + Return the current time, as a :class:`float` value, according to + the event loop's internal monotonic clock. + +.. note:: + .. versionchanged:: 3.8 + In Python 3.7 and earlier timeouts (relative *delay* or absolute *when*) + should not exceed one day. This has been fixed in Python 3.8. + +.. seealso:: + + The :func:`asyncio.sleep` function. + + +Creating Futures and Tasks +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. method:: loop.create_future() + + Create an :class:`asyncio.Future` object attached to the event loop. + + This is the preferred way to create Futures in asyncio. This lets + third-party event loops provide alternative implementations of + the Future object (with better performance or instrumentation). + + .. versionadded:: 3.5.2 + +.. method:: loop.create_task(coro, \*, name=None) + + Schedule the execution of a :ref:`coroutine`. + Return a :class:`Task` object. + + Third-party event loops can use their own subclass of :class:`Task` + for interoperability. In this case, the result type is a subclass + of :class:`Task`. + + If the *name* argument is provided and not ``None``, it is set as + the name of the task using :meth:`Task.set_name`. + + .. versionchanged:: 3.8 + Added the ``name`` parameter. + +.. method:: loop.set_task_factory(factory) + + Set a task factory that will be used by + :meth:`loop.create_task`. + + If *factory* is ``None`` the default task factory will be set. + Otherwise, *factory* must be a *callable* with the signature matching + ``(loop, coro)``, where *loop* is a reference to the active + event loop, and *coro* is a coroutine object. The callable + must return a :class:`asyncio.Future`-compatible object. + +.. method:: loop.get_task_factory() + + Return a task factory or ``None`` if the default one is in use. + + +Opening network connections +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. coroutinemethod:: loop.create_connection(protocol_factory, \ + host=None, port=None, \*, ssl=None, \ + family=0, proto=0, flags=0, sock=None, \ + local_addr=None, server_hostname=None, \ + ssl_handshake_timeout=None) + + Open a streaming transport connection to a given + address specified by *host* and *port*. + + The socket family can be either :py:data:`~socket.AF_INET` or + :py:data:`~socket.AF_INET6` depending on *host* (or the *family* + argument, if provided). + + The socket type will be :py:data:`~socket.SOCK_STREAM`. + + *protocol_factory* must be a callable returning an + :ref:`asyncio protocol ` implementation. + + This method will try to establish the connection in the background. + When successful, it returns a ``(transport, protocol)`` pair. + + The chronological synopsis of the underlying operation is as follows: + + #. The connection is established and a :ref:`transport ` + is created for it. + + #. *protocol_factory* is called without arguments and is expected to + return a :ref:`protocol ` instance. + + #. The protocol instance is coupled with the transport by calling its + :meth:`~BaseProtocol.connection_made` method. + + #. A ``(transport, protocol)`` tuple is returned on success. + + The created transport is an implementation-dependent bidirectional + stream. + + Other arguments: + + * *ssl*: if given and not false, a SSL/TLS transport is created + (by default a plain TCP transport is created). If *ssl* is + a :class:`ssl.SSLContext` object, this context is used to create + the transport; if *ssl* is :const:`True`, a default context returned + from :func:`ssl.create_default_context` is used. + + .. seealso:: :ref:`SSL/TLS security considerations ` + + * *server_hostname* sets or overrides the hostname that the target + server's certificate will be matched against. Should only be passed + if *ssl* is not ``None``. By default the value of the *host* argument + is used. If *host* is empty, there is no default and you must pass a + value for *server_hostname*. If *server_hostname* is an empty + string, hostname matching is disabled (which is a serious security + risk, allowing for potential man-in-the-middle attacks). + + * *family*, *proto*, *flags* are the optional address family, protocol + and flags to be passed through to getaddrinfo() for *host* resolution. + If given, these should all be integers from the corresponding + :mod:`socket` module constants. + + * *happy_eyeballs_delay*, if given, enables Happy Eyeballs for this + connection. It should + be a floating-point number representing the amount of time in seconds + to wait for a connection attempt to complete, before starting the next + attempt in parallel. This is the "Connection Attempt Delay" as defined + in :rfc:`8305`. A sensible default value recommended by the RFC is ``0.25`` + (250 milliseconds). + + * *interleave* controls address reordering when a host name resolves to + multiple IP addresses. + If ``0`` or unspecified, no reordering is done, and addresses are + tried in the order returned by :meth:`getaddrinfo`. If a positive integer + is specified, the addresses are interleaved by address family, and the + given integer is interpreted as "First Address Family Count" as defined + in :rfc:`8305`. The default is ``0`` if *happy_eyeballs_delay* is not + specified, and ``1`` if it is. + + * *sock*, if given, should be an existing, already connected + :class:`socket.socket` object to be used by the transport. + If *sock* is given, none of *host*, *port*, *family*, *proto*, *flags*, + *happy_eyeballs_delay*, *interleave* + and *local_addr* should be specified. + + * *local_addr*, if given, is a ``(local_host, local_port)`` tuple used + to bind the socket to locally. The *local_host* and *local_port* + are looked up using ``getaddrinfo()``, similarly to *host* and *port*. + + * *ssl_handshake_timeout* is (for a TLS connection) the time in seconds + to wait for the TLS handshake to complete before aborting the connection. + ``60.0`` seconds if ``None`` (default). + + .. versionadded:: 3.8 + + The *happy_eyeballs_delay* and *interleave* parameters. + + .. versionadded:: 3.7 + + The *ssl_handshake_timeout* parameter. + + .. versionchanged:: 3.6 + + The socket option :py:data:`~socket.TCP_NODELAY` is set by default + for all TCP connections. + + .. versionchanged:: 3.5 + + Added support for SSL/TLS in :class:`ProactorEventLoop`. + + .. seealso:: + + The :func:`open_connection` function is a high-level alternative + API. It returns a pair of (:class:`StreamReader`, :class:`StreamWriter`) + that can be used directly in async/await code. + +.. coroutinemethod:: loop.create_datagram_endpoint(protocol_factory, \ + local_addr=None, remote_addr=None, \*, \ + family=0, proto=0, flags=0, \ + reuse_address=None, reuse_port=None, \ + allow_broadcast=None, sock=None) + + Create a datagram connection. + + The socket family can be either :py:data:`~socket.AF_INET`, + :py:data:`~socket.AF_INET6`, or :py:data:`~socket.AF_UNIX`, + depending on *host* (or the *family* argument, if provided). + + The socket type will be :py:data:`~socket.SOCK_DGRAM`. + + *protocol_factory* must be a callable returning a + :ref:`protocol ` implementation. + + A tuple of ``(transport, protocol)`` is returned on success. + + Other arguments: + + * *local_addr*, if given, is a ``(local_host, local_port)`` tuple used + to bind the socket to locally. The *local_host* and *local_port* + are looked up using :meth:`getaddrinfo`. + + * *remote_addr*, if given, is a ``(remote_host, remote_port)`` tuple used + to connect the socket to a remote address. The *remote_host* and + *remote_port* are looked up using :meth:`getaddrinfo`. + + * *family*, *proto*, *flags* are the optional address family, protocol + and flags to be passed through to :meth:`getaddrinfo` for *host* + resolution. If given, these should all be integers from the + corresponding :mod:`socket` module constants. + + * *reuse_address* tells the kernel to reuse a local socket in + ``TIME_WAIT`` state, without waiting for its natural timeout to + expire. If not specified will automatically be set to ``True`` on + Unix. + + * *reuse_port* tells the kernel to allow this endpoint to be bound to the + same port as other existing endpoints are bound to, so long as they all + set this flag when being created. This option is not supported on Windows + and some Unixes. If the :py:data:`~socket.SO_REUSEPORT` constant is not + defined then this capability is unsupported. + + * *allow_broadcast* tells the kernel to allow this endpoint to send + messages to the broadcast address. + + * *sock* can optionally be specified in order to use a preexisting, + already connected, :class:`socket.socket` object to be used by the + transport. If specified, *local_addr* and *remote_addr* should be omitted + (must be :const:`None`). + + See :ref:`UDP echo client protocol ` and + :ref:`UDP echo server protocol ` examples. + + .. versionchanged:: 3.4.4 + The *family*, *proto*, *flags*, *reuse_address*, *reuse_port, + *allow_broadcast*, and *sock* parameters were added. + + .. versionchanged:: 3.8 + Added support for Windows. + +.. coroutinemethod:: loop.create_unix_connection(protocol_factory, \ + path=None, \*, ssl=None, sock=None, \ + server_hostname=None, ssl_handshake_timeout=None) + + Create a Unix connection. + + The socket family will be :py:data:`~socket.AF_UNIX`; socket + type will be :py:data:`~socket.SOCK_STREAM`. + + A tuple of ``(transport, protocol)`` is returned on success. + + *path* is the name of a Unix domain socket and is required, + unless a *sock* parameter is specified. Abstract Unix sockets, + :class:`str`, :class:`bytes`, and :class:`~pathlib.Path` paths are + supported. + + See the documentation of the :meth:`loop.create_connection` method + for information about arguments to this method. + + .. availability:: Unix. + + .. versionadded:: 3.7 + + The *ssl_handshake_timeout* parameter. + + .. versionchanged:: 3.7 + + The *path* parameter can now be a :term:`path-like object`. + + +Creating network servers +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. coroutinemethod:: loop.create_server(protocol_factory, \ + host=None, port=None, \*, \ + family=socket.AF_UNSPEC, \ + flags=socket.AI_PASSIVE, \ + sock=None, backlog=100, ssl=None, \ + reuse_address=None, reuse_port=None, \ + ssl_handshake_timeout=None, start_serving=True) + + Create a TCP server (socket type :data:`~socket.SOCK_STREAM`) listening + on *port* of the *host* address. + + Returns a :class:`Server` object. + + Arguments: + + * *protocol_factory* must be a callable returning a + :ref:`protocol ` implementation. + + * The *host* parameter can be set to several types which determine where + the server would be listening: + + - If *host* is a string, the TCP server is bound to a single network + interface specified by *host*. + + - If *host* is a sequence of strings, the TCP server is bound to all + network interfaces specified by the sequence. + + - If *host* is an empty string or ``None``, all interfaces are + assumed and a list of multiple sockets will be returned (most likely + one for IPv4 and another one for IPv6). + + * *family* can be set to either :data:`socket.AF_INET` or + :data:`~socket.AF_INET6` to force the socket to use IPv4 or IPv6. + If not set, the *family* will be determined from host name + (defaults to :data:`~socket.AF_UNSPEC`). + + * *flags* is a bitmask for :meth:`getaddrinfo`. + + * *sock* can optionally be specified in order to use a preexisting + socket object. If specified, *host* and *port* must not be specified. + + * *backlog* is the maximum number of queued connections passed to + :meth:`~socket.socket.listen` (defaults to 100). + + * *ssl* can be set to an :class:`~ssl.SSLContext` instance to enable + TLS over the accepted connections. + + * *reuse_address* tells the kernel to reuse a local socket in + ``TIME_WAIT`` state, without waiting for its natural timeout to + expire. If not specified will automatically be set to ``True`` on + Unix. + + * *reuse_port* tells the kernel to allow this endpoint to be bound to the + same port as other existing endpoints are bound to, so long as they all + set this flag when being created. This option is not supported on + Windows. + + * *ssl_handshake_timeout* is (for a TLS server) the time in seconds to wait + for the TLS handshake to complete before aborting the connection. + ``60.0`` seconds if ``None`` (default). + + * *start_serving* set to ``True`` (the default) causes the created server + to start accepting connections immediately. When set to ``False``, + the user should await on :meth:`Server.start_serving` or + :meth:`Server.serve_forever` to make the server to start accepting + connections. + + .. versionadded:: 3.7 + + Added *ssl_handshake_timeout* and *start_serving* parameters. + + .. versionchanged:: 3.6 + + The socket option :py:data:`~socket.TCP_NODELAY` is set by default + for all TCP connections. + + .. versionchanged:: 3.5 + + Added support for SSL/TLS in :class:`ProactorEventLoop`. + + .. versionchanged:: 3.5.1 + + The *host* parameter can be a sequence of strings. + + .. seealso:: + + The :func:`start_server` function is a higher-level alternative API + that returns a pair of :class:`StreamReader` and :class:`StreamWriter` + that can be used in an async/await code. + + +.. coroutinemethod:: loop.create_unix_server(protocol_factory, path=None, \ + \*, sock=None, backlog=100, ssl=None, \ + ssl_handshake_timeout=None, start_serving=True) + + Similar to :meth:`loop.create_server` but works with the + :py:data:`~socket.AF_UNIX` socket family. + + *path* is the name of a Unix domain socket, and is required, + unless a *sock* argument is provided. Abstract Unix sockets, + :class:`str`, :class:`bytes`, and :class:`~pathlib.Path` paths + are supported. + + See the documentation of the :meth:`loop.create_server` method + for information about arguments to this method. + + .. availability:: Unix. + + .. versionadded:: 3.7 + + The *ssl_handshake_timeout* and *start_serving* parameters. + + .. versionchanged:: 3.7 + + The *path* parameter can now be a :class:`~pathlib.Path` object. + +.. coroutinemethod:: loop.connect_accepted_socket(protocol_factory, \ + sock, \*, ssl=None, ssl_handshake_timeout=None) + + Wrap an already accepted connection into a transport/protocol pair. + + This method can be used by servers that accept connections outside + of asyncio but that use asyncio to handle them. + + Parameters: + + * *protocol_factory* must be a callable returning a + :ref:`protocol ` implementation. + + * *sock* is a preexisting socket object returned from + :meth:`socket.accept `. + + * *ssl* can be set to an :class:`~ssl.SSLContext` to enable SSL over + the accepted connections. + + * *ssl_handshake_timeout* is (for an SSL connection) the time in seconds to + wait for the SSL handshake to complete before aborting the connection. + ``60.0`` seconds if ``None`` (default). + + Returns a ``(transport, protocol)`` pair. + + .. versionadded:: 3.7 + + The *ssl_handshake_timeout* parameter. + + .. versionadded:: 3.5.3 + + +Transferring files +^^^^^^^^^^^^^^^^^^ + +.. coroutinemethod:: loop.sendfile(transport, file, \ + offset=0, count=None, *, fallback=True) + + Send a *file* over a *transport*. Return the total number of bytes + sent. + + The method uses high-performance :meth:`os.sendfile` if available. + + *file* must be a regular file object opened in binary mode. + + *offset* tells from where to start reading the file. If specified, + *count* is the total number of bytes to transmit as opposed to + sending the file until EOF is reached. File position is always updated, + even when this method raises an error, and + :meth:`file.tell() ` can be used to obtain the actual + number of bytes sent. + + *fallback* set to ``True`` makes asyncio to manually read and send + the file when the platform does not support the sendfile system call + (e.g. Windows or SSL socket on Unix). + + Raise :exc:`SendfileNotAvailableError` if the system does not support + the *sendfile* syscall and *fallback* is ``False``. + + .. versionadded:: 3.7 + + +TLS Upgrade +^^^^^^^^^^^ + +.. coroutinemethod:: loop.start_tls(transport, protocol, \ + sslcontext, \*, server_side=False, \ + server_hostname=None, ssl_handshake_timeout=None) + + Upgrade an existing transport-based connection to TLS. + + Return a new transport instance, that the *protocol* must start using + immediately after the *await*. The *transport* instance passed to + the *start_tls* method should never be used again. + + Parameters: + + * *transport* and *protocol* instances that methods like + :meth:`~loop.create_server` and + :meth:`~loop.create_connection` return. + + * *sslcontext*: a configured instance of :class:`~ssl.SSLContext`. + + * *server_side* pass ``True`` when a server-side connection is being + upgraded (like the one created by :meth:`~loop.create_server`). + + * *server_hostname*: sets or overrides the host name that the target + server's certificate will be matched against. + + * *ssl_handshake_timeout* is (for a TLS connection) the time in seconds to + wait for the TLS handshake to complete before aborting the connection. + ``60.0`` seconds if ``None`` (default). + + .. versionadded:: 3.7 + + +Watching file descriptors +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. method:: loop.add_reader(fd, callback, \*args) + + Start monitoring the *fd* file descriptor for read availability and + invoke *callback* with the specified arguments once *fd* is available for + reading. + +.. method:: loop.remove_reader(fd) + + Stop monitoring the *fd* file descriptor for read availability. + +.. method:: loop.add_writer(fd, callback, \*args) + + Start monitoring the *fd* file descriptor for write availability and + invoke *callback* with the specified arguments once *fd* is available for + writing. + + Use :func:`functools.partial` :ref:`to pass keyword arguments + ` to *callback*. + +.. method:: loop.remove_writer(fd) + + Stop monitoring the *fd* file descriptor for write availability. + +See also :ref:`Platform Support ` section +for some limitations of these methods. + + +Working with socket objects directly +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In general, protocol implementations that use transport-based APIs +such as :meth:`loop.create_connection` and :meth:`loop.create_server` +are faster than implementations that work with sockets directly. +However, there are some use cases when performance is not critical, and +working with :class:`~socket.socket` objects directly is more +convenient. + +.. coroutinemethod:: loop.sock_recv(sock, nbytes) + + Receive up to *nbytes* from *sock*. Asynchronous version of + :meth:`socket.recv() `. + + Return the received data as a bytes object. + + *sock* must be a non-blocking socket. + + .. versionchanged:: 3.7 + Even though this method was always documented as a coroutine + method, releases before Python 3.7 returned a :class:`Future`. + Since Python 3.7 this is an ``async def`` method. + +.. coroutinemethod:: loop.sock_recv_into(sock, buf) + + Receive data from *sock* into the *buf* buffer. Modeled after the blocking + :meth:`socket.recv_into() ` method. + + Return the number of bytes written to the buffer. + + *sock* must be a non-blocking socket. + + .. versionadded:: 3.7 + +.. coroutinemethod:: loop.sock_sendall(sock, data) + + Send *data* to the *sock* socket. Asynchronous version of + :meth:`socket.sendall() `. + + This method continues to send to the socket until either all data + in *data* has been sent or an error occurs. ``None`` is returned + on success. On error, an exception is raised. Additionally, there is no way + to determine how much data, if any, was successfully processed by the + receiving end of the connection. + + *sock* must be a non-blocking socket. + + .. versionchanged:: 3.7 + Even though the method was always documented as a coroutine + method, before Python 3.7 it returned an :class:`Future`. + Since Python 3.7, this is an ``async def`` method. + +.. coroutinemethod:: loop.sock_connect(sock, address) + + Connect *sock* to a remote socket at *address*. + + Asynchronous version of :meth:`socket.connect() `. + + *sock* must be a non-blocking socket. + + .. versionchanged:: 3.5.2 + ``address`` no longer needs to be resolved. ``sock_connect`` + will try to check if the *address* is already resolved by calling + :func:`socket.inet_pton`. If not, + :meth:`loop.getaddrinfo` will be used to resolve the + *address*. + + .. seealso:: + + :meth:`loop.create_connection` + and :func:`asyncio.open_connection() `. + + +.. coroutinemethod:: loop.sock_accept(sock) + + Accept a connection. Modeled after the blocking + :meth:`socket.accept() ` method. + + The socket must be bound to an address and listening + for connections. The return value is a pair ``(conn, address)`` where *conn* + is a *new* socket object usable to send and receive data on the connection, + and *address* is the address bound to the socket on the other end of the + connection. + + *sock* must be a non-blocking socket. + + .. versionchanged:: 3.7 + Even though the method was always documented as a coroutine + method, before Python 3.7 it returned a :class:`Future`. + Since Python 3.7, this is an ``async def`` method. + + .. seealso:: + + :meth:`loop.create_server` and :func:`start_server`. + +.. coroutinemethod:: loop.sock_sendfile(sock, file, offset=0, count=None, \ + \*, fallback=True) + + Send a file using high-performance :mod:`os.sendfile` if possible. + Return the total number of bytes sent. + + Asynchronous version of :meth:`socket.sendfile() `. + + *sock* must be a non-blocking :const:`socket.SOCK_STREAM` + :class:`~socket.socket`. + + *file* must be a regular file object open in binary mode. + + *offset* tells from where to start reading the file. If specified, + *count* is the total number of bytes to transmit as opposed to + sending the file until EOF is reached. File position is always updated, + even when this method raises an error, and + :meth:`file.tell() ` can be used to obtain the actual + number of bytes sent. + + *fallback*, when set to ``True``, makes asyncio manually read and send + the file when the platform does not support the sendfile syscall + (e.g. Windows or SSL socket on Unix). + + Raise :exc:`SendfileNotAvailableError` if the system does not support + *sendfile* syscall and *fallback* is ``False``. + + *sock* must be a non-blocking socket. + + .. versionadded:: 3.7 + + +DNS +^^^ + +.. coroutinemethod:: loop.getaddrinfo(host, port, \*, family=0, \ + type=0, proto=0, flags=0) + + Asynchronous version of :meth:`socket.getaddrinfo`. + +.. coroutinemethod:: loop.getnameinfo(sockaddr, flags=0) + + Asynchronous version of :meth:`socket.getnameinfo`. + +.. versionchanged:: 3.7 + Both *getaddrinfo* and *getnameinfo* methods were always documented + to return a coroutine, but prior to Python 3.7 they were, in fact, + returning :class:`asyncio.Future` objects. Starting with Python 3.7 + both methods are coroutines. + + +Working with pipes +^^^^^^^^^^^^^^^^^^ + +.. coroutinemethod:: loop.connect_read_pipe(protocol_factory, pipe) + + Register the read end of *pipe* in the event loop. + + *protocol_factory* must be a callable returning an + :ref:`asyncio protocol ` implementation. + + *pipe* is a :term:`file-like object `. + + Return pair ``(transport, protocol)``, where *transport* supports + the :class:`ReadTransport` interface and *protocol* is an object + instantiated by the *protocol_factory*. + + With :class:`SelectorEventLoop` event loop, the *pipe* is set to + non-blocking mode. + +.. coroutinemethod:: loop.connect_write_pipe(protocol_factory, pipe) + + Register the write end of *pipe* in the event loop. + + *protocol_factory* must be a callable returning an + :ref:`asyncio protocol ` implementation. + + *pipe* is :term:`file-like object `. + + Return pair ``(transport, protocol)``, where *transport* supports + :class:`WriteTransport` interface and *protocol* is an object + instantiated by the *protocol_factory*. + + With :class:`SelectorEventLoop` event loop, the *pipe* is set to + non-blocking mode. + +.. note:: + + :class:`SelectorEventLoop` does not support the above methods on + Windows. Use :class:`ProactorEventLoop` instead for Windows. + +.. seealso:: + + The :meth:`loop.subprocess_exec` and + :meth:`loop.subprocess_shell` methods. + + +Unix signals +^^^^^^^^^^^^ + +.. method:: loop.add_signal_handler(signum, callback, \*args) + + Set *callback* as the handler for the *signum* signal. + + The callback will be invoked by *loop*, along with other queued callbacks + and runnable coroutines of that event loop. Unlike signal handlers + registered using :func:`signal.signal`, a callback registered with this + function is allowed to interact with the event loop. + + Raise :exc:`ValueError` if the signal number is invalid or uncatchable. + Raise :exc:`RuntimeError` if there is a problem setting up the handler. + + Use :func:`functools.partial` :ref:`to pass keyword arguments + ` to *callback*. + + Like :func:`signal.signal`, this function must be invoked in the main + thread. + +.. method:: loop.remove_signal_handler(sig) + + Remove the handler for the *sig* signal. + + Return ``True`` if the signal handler was removed, or ``False`` if + no handler was set for the given signal. + + .. availability:: Unix. + +.. seealso:: + + The :mod:`signal` module. + + +Executing code in thread or process pools +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. awaitablemethod:: loop.run_in_executor(executor, func, \*args) + + Arrange for *func* to be called in the specified executor. + + The *executor* argument should be an :class:`concurrent.futures.Executor` + instance. The default executor is used if *executor* is ``None``. + + Example:: + + import asyncio + import concurrent.futures + + def blocking_io(): + # File operations (such as logging) can block the + # event loop: run them in a thread pool. + with open('/dev/urandom', 'rb') as f: + return f.read(100) + + def cpu_bound(): + # CPU-bound operations will block the event loop: + # in general it is preferable to run them in a + # process pool. + return sum(i * i for i in range(10 ** 7)) + + async def main(): + loop = asyncio.get_running_loop() + + ## Options: + + # 1. Run in the default loop's executor: + result = await loop.run_in_executor( + None, blocking_io) + print('default thread pool', result) + + # 2. Run in a custom thread pool: + with concurrent.futures.ThreadPoolExecutor() as pool: + result = await loop.run_in_executor( + pool, blocking_io) + print('custom thread pool', result) + + # 3. Run in a custom process pool: + with concurrent.futures.ProcessPoolExecutor() as pool: + result = await loop.run_in_executor( + pool, cpu_bound) + print('custom process pool', result) + + asyncio.run(main()) + + This method returns a :class:`asyncio.Future` object. + + Use :func:`functools.partial` :ref:`to pass keyword arguments + ` to *func*. + + .. versionchanged:: 3.5.3 + :meth:`loop.run_in_executor` no longer configures the + ``max_workers`` of the thread pool executor it creates, instead + leaving it up to the thread pool executor + (:class:`~concurrent.futures.ThreadPoolExecutor`) to set the + default. + +.. method:: loop.set_default_executor(executor) + + Set *executor* as the default executor used by :meth:`run_in_executor`. + *executor* should be an instance of + :class:`~concurrent.futures.ThreadPoolExecutor`. + + .. deprecated:: 3.8 + Using an executor that is not an instance of + :class:`~concurrent.futures.ThreadPoolExecutor` is deprecated and + will trigger an error in Python 3.9. + + *executor* must be an instance of + :class:`concurrent.futures.ThreadPoolExecutor`. + + +Error Handling API +^^^^^^^^^^^^^^^^^^ + +Allows customizing how exceptions are handled in the event loop. + +.. method:: loop.set_exception_handler(handler) + + Set *handler* as the new event loop exception handler. + + If *handler* is ``None``, the default exception handler will + be set. Otherwise, *handler* must be a callable with the signature + matching ``(loop, context)``, where ``loop`` + is a reference to the active event loop, and ``context`` + is a ``dict`` object containing the details of the exception + (see :meth:`call_exception_handler` documentation for details + about context). + +.. method:: loop.get_exception_handler() + + Return the current exception handler, or ``None`` if no custom + exception handler was set. + + .. versionadded:: 3.5.2 + +.. method:: loop.default_exception_handler(context) + + Default exception handler. + + This is called when an exception occurs and no exception + handler is set. This can be called by a custom exception + handler that wants to defer to the default handler behavior. + + *context* parameter has the same meaning as in + :meth:`call_exception_handler`. + +.. method:: loop.call_exception_handler(context) + + Call the current event loop exception handler. + + *context* is a ``dict`` object containing the following keys + (new keys may be introduced in future Python versions): + + * 'message': Error message; + * 'exception' (optional): Exception object; + * 'future' (optional): :class:`asyncio.Future` instance; + * 'handle' (optional): :class:`asyncio.Handle` instance; + * 'protocol' (optional): :ref:`Protocol ` instance; + * 'transport' (optional): :ref:`Transport ` instance; + * 'socket' (optional): :class:`socket.socket` instance. + + .. note:: + + This method should not be overloaded in subclassed + event loops. For custom exception handling, use + the :meth:`set_exception_handler()` method. + +Enabling debug mode +^^^^^^^^^^^^^^^^^^^ + +.. method:: loop.get_debug() + + Get the debug mode (:class:`bool`) of the event loop. + + The default value is ``True`` if the environment variable + :envvar:`PYTHONASYNCIODEBUG` is set to a non-empty string, ``False`` + otherwise. + +.. method:: loop.set_debug(enabled: bool) + + Set the debug mode of the event loop. + + .. versionchanged:: 3.7 + + The new ``-X dev`` command line option can now also be used + to enable the debug mode. + +.. seealso:: + + The :ref:`debug mode of asyncio `. + + +Running Subprocesses +^^^^^^^^^^^^^^^^^^^^ + +Methods described in this subsections are low-level. In regular +async/await code consider using the high-level +:func:`asyncio.create_subprocess_shell` and +:func:`asyncio.create_subprocess_exec` convenience functions instead. + +.. note:: + + The default asyncio event loop on **Windows** does not support + subprocesses. See :ref:`Subprocess Support on Windows + ` for details. + +.. coroutinemethod:: loop.subprocess_exec(protocol_factory, \*args, \ + stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ + stderr=subprocess.PIPE, \*\*kwargs) + + Create a subprocess from one or more string arguments specified by + *args*. + + *args* must be a list of strings represented by: + + * :class:`str`; + * or :class:`bytes`, encoded to the + :ref:`filesystem encoding `. + + The first string specifies the program executable, + and the remaining strings specify the arguments. Together, string + arguments form the ``argv`` of the program. + + This is similar to the standard library :class:`subprocess.Popen` + class called with ``shell=False`` and the list of strings passed as + the first argument; however, where :class:`~subprocess.Popen` takes + a single argument which is list of strings, *subprocess_exec* + takes multiple string arguments. + + The *protocol_factory* must be a callable returning a subclass of the + :class:`asyncio.SubprocessProtocol` class. + + Other parameters: + + * *stdin* can be any of these: + + * a file-like object representing a pipe to be connected to the + subprocess's standard input stream using + :meth:`~loop.connect_write_pipe` + * the :const:`subprocess.PIPE` constant (default) which will create a new + pipe and connect it, + * the value ``None`` which will make the subprocess inherit the file + descriptor from this process + * the :const:`subprocess.DEVNULL` constant which indicates that the + special :data:`os.devnull` file will be used + + * *stdout* can be any of these: + + * a file-like object representing a pipe to be connected to the + subprocess's standard output stream using + :meth:`~loop.connect_write_pipe` + * the :const:`subprocess.PIPE` constant (default) which will create a new + pipe and connect it, + * the value ``None`` which will make the subprocess inherit the file + descriptor from this process + * the :const:`subprocess.DEVNULL` constant which indicates that the + special :data:`os.devnull` file will be used + + * *stderr* can be any of these: + + * a file-like object representing a pipe to be connected to the + subprocess's standard error stream using + :meth:`~loop.connect_write_pipe` + * the :const:`subprocess.PIPE` constant (default) which will create a new + pipe and connect it, + * the value ``None`` which will make the subprocess inherit the file + descriptor from this process + * the :const:`subprocess.DEVNULL` constant which indicates that the + special :data:`os.devnull` file will be used + * the :const:`subprocess.STDOUT` constant which will connect the standard + error stream to the process' standard output stream + + * All other keyword arguments are passed to :class:`subprocess.Popen` + without interpretation, except for *bufsize*, *universal_newlines*, + *shell*, *text*, *encoding* and *errors*, which should not be specified + at all. + + The ``asyncio`` subprocess API does not support decoding the streams + as text. :func:`bytes.decode` can be used to convert the bytes returned + from the stream to text. + + See the constructor of the :class:`subprocess.Popen` class + for documentation on other arguments. + + Returns a pair of ``(transport, protocol)``, where *transport* + conforms to the :class:`asyncio.SubprocessTransport` base class and + *protocol* is an object instantiated by the *protocol_factory*. + +.. coroutinemethod:: loop.subprocess_shell(protocol_factory, cmd, \*, \ + stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ + stderr=subprocess.PIPE, \*\*kwargs) + + Create a subprocess from *cmd*, which can be a :class:`str` or a + :class:`bytes` string encoded to the + :ref:`filesystem encoding `, + using the platform's "shell" syntax. + + This is similar to the standard library :class:`subprocess.Popen` + class called with ``shell=True``. + + The *protocol_factory* must be a callable returning a subclass of the + :class:`SubprocessProtocol` class. + + See :meth:`~loop.subprocess_exec` for more details about + the remaining arguments. + + Returns a pair of ``(transport, protocol)``, where *transport* + conforms to the :class:`SubprocessTransport` base class and + *protocol* is an object instantiated by the *protocol_factory*. + +.. note:: + It is the application's responsibility to ensure that all whitespace + and special characters are quoted appropriately to avoid `shell injection + `_ + vulnerabilities. The :func:`shlex.quote` function can be used to + properly escape whitespace and special characters in strings that + are going to be used to construct shell commands. + + +Callback Handles +================ + +.. class:: Handle + + A callback wrapper object returned by :meth:`loop.call_soon`, + :meth:`loop.call_soon_threadsafe`. + + .. method:: cancel() + + Cancel the callback. If the callback has already been canceled + or executed, this method has no effect. + + .. method:: cancelled() + + Return ``True`` if the callback was cancelled. + + .. versionadded:: 3.7 + +.. class:: TimerHandle + + A callback wrapper object returned by :meth:`loop.call_later`, + and :meth:`loop.call_at`. + + This class is a subclass of :class:`Handle`. + + .. method:: when() + + Return a scheduled callback time as :class:`float` seconds. + + The time is an absolute timestamp, using the same time + reference as :meth:`loop.time`. + + .. versionadded:: 3.7 + + +Server Objects +============== + +Server objects are created by :meth:`loop.create_server`, +:meth:`loop.create_unix_server`, :func:`start_server`, +and :func:`start_unix_server` functions. + +Do not instantiate the class directly. + +.. class:: Server + + *Server* objects are asynchronous context managers. When used in an + ``async with`` statement, it's guaranteed that the Server object is + closed and not accepting new connections when the ``async with`` + statement is completed:: + + srv = await loop.create_server(...) + + async with srv: + # some code + + # At this point, srv is closed and no longer accepts new connections. + + + .. versionchanged:: 3.7 + Server object is an asynchronous context manager since Python 3.7. + + .. method:: close() + + Stop serving: close listening sockets and set the :attr:`sockets` + attribute to ``None``. + + The sockets that represent existing incoming client connections + are left open. + + The server is closed asynchronously, use the :meth:`wait_closed` + coroutine to wait until the server is closed. + + .. method:: get_loop() + + Return the event loop associated with the server object. + + .. versionadded:: 3.7 + + .. coroutinemethod:: start_serving() + + Start accepting connections. + + This method is idempotent, so it can be called when + the server is already being serving. + + The *start_serving* keyword-only parameter to + :meth:`loop.create_server` and + :meth:`asyncio.start_server` allows creating a Server object + that is not accepting connections initially. In this case + ``Server.start_serving()``, or :meth:`Server.serve_forever` can be used + to make the Server start accepting connections. + + .. versionadded:: 3.7 + + .. coroutinemethod:: serve_forever() + + Start accepting connections until the coroutine is cancelled. + Cancellation of ``serve_forever`` task causes the server + to be closed. + + This method can be called if the server is already accepting + connections. Only one ``serve_forever`` task can exist per + one *Server* object. + + Example:: + + async def client_connected(reader, writer): + # Communicate with the client with + # reader/writer streams. For example: + await reader.readline() + + async def main(host, port): + srv = await asyncio.start_server( + client_connected, host, port) + await srv.serve_forever() + + asyncio.run(main('127.0.0.1', 0)) + + .. versionadded:: 3.7 + + .. method:: is_serving() + + Return ``True`` if the server is accepting new connections. + + .. versionadded:: 3.7 + + .. coroutinemethod:: wait_closed() + + Wait until the :meth:`close` method completes. + + .. attribute:: sockets + + List of :class:`socket.socket` objects the server is listening on. + + .. versionchanged:: 3.7 + Prior to Python 3.7 ``Server.sockets`` used to return an + internal list of server sockets directly. In 3.7 a copy + of that list is returned. + + +.. _asyncio-event-loops: + +Event Loop Implementations +========================== + +asyncio ships with two different event loop implementations: +:class:`SelectorEventLoop` and :class:`ProactorEventLoop`. + +By default asyncio is configured to use :class:`SelectorEventLoop` +on Unix and :class:`ProactorEventLoop` on Windows. + + +.. class:: SelectorEventLoop + + An event loop based on the :mod:`selectors` module. + + Uses the most efficient *selector* available for the given + platform. It is also possible to manually configure the + exact selector implementation to be used:: + + import asyncio + import selectors + + selector = selectors.SelectSelector() + loop = asyncio.SelectorEventLoop(selector) + asyncio.set_event_loop(loop) + + + .. availability:: Unix, Windows. + + +.. class:: ProactorEventLoop + + An event loop for Windows that uses "I/O Completion Ports" (IOCP). + + .. availability:: Windows. + + .. seealso:: + + `MSDN documentation on I/O Completion Ports + `_. + + +.. class:: AbstractEventLoop + + Abstract base class for asyncio-compliant event loops. + + The :ref:`Event Loop Methods ` section lists all + methods that an alternative implementation of ``AbstractEventLoop`` + should have defined. + + +Examples +======== + +Note that all examples in this section **purposefully** show how +to use the low-level event loop APIs, such as :meth:`loop.run_forever` +and :meth:`loop.call_soon`. Modern asyncio applications rarely +need to be written this way; consider using the high-level functions +like :func:`asyncio.run`. + + +.. _asyncio_example_lowlevel_helloworld: + +Hello World with call_soon() +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An example using the :meth:`loop.call_soon` method to schedule a +callback. The callback displays ``"Hello World"`` and then stops the +event loop:: + + import asyncio + + def hello_world(loop): + """A callback to print 'Hello World' and stop the event loop""" + print('Hello World') + loop.stop() + + loop = asyncio.get_event_loop() + + # Schedule a call to hello_world() + loop.call_soon(hello_world, loop) + + # Blocking call interrupted by loop.stop() + try: + loop.run_forever() + finally: + loop.close() + +.. seealso:: + + A similar :ref:`Hello World ` + example created with a coroutine and the :func:`run` function. + + +.. _asyncio_example_call_later: + +Display the current date with call_later() +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An example of a callback displaying the current date every second. The +callback uses the :meth:`loop.call_later` method to reschedule itself +after 5 seconds, and then stops the event loop:: + + import asyncio + import datetime + + def display_date(end_time, loop): + print(datetime.datetime.now()) + if (loop.time() + 1.0) < end_time: + loop.call_later(1, display_date, end_time, loop) + else: + loop.stop() + + loop = asyncio.get_event_loop() + + # Schedule the first call to display_date() + end_time = loop.time() + 5.0 + loop.call_soon(display_date, end_time, loop) + + # Blocking call interrupted by loop.stop() + try: + loop.run_forever() + finally: + loop.close() + +.. seealso:: + + A similar :ref:`current date ` example + created with a coroutine and the :func:`run` function. + + +.. _asyncio_example_watch_fd: + +Watch a file descriptor for read events +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Wait until a file descriptor received some data using the +:meth:`loop.add_reader` method and then close the event loop:: + + import asyncio + from socket import socketpair + + # Create a pair of connected file descriptors + rsock, wsock = socketpair() + + loop = asyncio.get_event_loop() + + def reader(): + data = rsock.recv(100) + print("Received:", data.decode()) + + # We are done: unregister the file descriptor + loop.remove_reader(rsock) + + # Stop the event loop + loop.stop() + + # Register the file descriptor for read event + loop.add_reader(rsock, reader) + + # Simulate the reception of data from the network + loop.call_soon(wsock.send, 'abc'.encode()) + + try: + # Run the event loop + loop.run_forever() + finally: + # We are done. Close sockets and the event loop. + rsock.close() + wsock.close() + loop.close() + +.. seealso:: + + * A similar :ref:`example ` + using transports, protocols, and the + :meth:`loop.create_connection` method. + + * Another similar :ref:`example ` + using the high-level :func:`asyncio.connect` function and streams. + + +.. _asyncio_example_unix_signals: + +Set signal handlers for SIGINT and SIGTERM +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +(This ``signals`` example only works on Unix.) + +Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM` +using the :meth:`loop.add_signal_handler` method:: + + import asyncio + import functools + import os + import signal + + def ask_exit(signame, loop): + print("got signal %s: exit" % signame) + loop.stop() + + async def main(): + loop = asyncio.get_running_loop() + + for signame in {'SIGINT', 'SIGTERM'}: + loop.add_signal_handler( + getattr(signal, signame), + functools.partial(ask_exit, signame, loop)) + + await asyncio.sleep(3600) + + print("Event loop running for 1 hour, press Ctrl+C to interrupt.") + print(f"pid {os.getpid()}: send SIGINT or SIGTERM to exit.") + + asyncio.run(main()) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 4a7aaf3e2fb1bd..031071281b38f7 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -552,6 +552,8 @@ async def shutdown_asyncgens(self): 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() @@ -562,7 +564,7 @@ async def shutdown_default_executor(self): def _do_shutdown(self, future): try: - self._executor.shutdown(wait=True) + 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) From 5340a5c84dabaefaa4091035aea472b4f2e64547 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 11 Sep 2019 16:53:08 -0400 Subject: [PATCH 21/26] Delete accidentally committed temp file --- Doc/library/asyncio-eventloop.rst.bak | 1675 ------------------------- 1 file changed, 1675 deletions(-) delete mode 100644 Doc/library/asyncio-eventloop.rst.bak diff --git a/Doc/library/asyncio-eventloop.rst.bak b/Doc/library/asyncio-eventloop.rst.bak deleted file mode 100644 index 3823bef9eb87e5..00000000000000 --- a/Doc/library/asyncio-eventloop.rst.bak +++ /dev/null @@ -1,1675 +0,0 @@ -.. currentmodule:: asyncio - - -========== -Event Loop -========== - - -.. rubric:: Preface - -The event loop is the core of every asyncio application. -Event loops run asynchronous tasks and callbacks, perform network -IO operations, and run subprocesses. - -Application developers should typically use the high-level asyncio functions, -such as :func:`asyncio.run`, and should rarely need to reference the loop -object or call its methods. This section is intended mostly for authors -of lower-level code, libraries, and frameworks, who need finer control over -the event loop behavior. - -.. rubric:: Obtaining the Event Loop - -The following low-level functions can be used to get, set, or create -an event loop: - -.. function:: get_running_loop() - - Return the running event loop in the current OS thread. - - If there is no running event loop a :exc:`RuntimeError` is raised. - This function can only be called from a coroutine or a callback. - - .. versionadded:: 3.7 - -.. function:: get_event_loop() - - Get the current event loop. If there is no current event loop set - in the current OS thread and :func:`set_event_loop` has not yet - been called, asyncio will create a new event loop and set it as the - current one. - - Because this function has rather complex behavior (especially - when custom event loop policies are in use), using the - :func:`get_running_loop` function is preferred to :func:`get_event_loop` - in coroutines and callbacks. - - Consider also using the :func:`asyncio.run` function instead of using - lower level functions to manually create and close an event loop. - -.. function:: set_event_loop(loop) - - Set *loop* as a current event loop for the current OS thread. - -.. function:: new_event_loop() - - Create a new event loop object. - -Note that the behaviour of :func:`get_event_loop`, :func:`set_event_loop`, -and :func:`new_event_loop` functions can be altered by -:ref:`setting a custom event loop policy `. - - -.. rubric:: Contents - -This documentation page contains the following sections: - -* The `Event Loop Methods`_ section is the reference documentation of - the event loop APIs; - -* The `Callback Handles`_ section documents the :class:`Handle` and - :class:`TimerHandle` instances which are returned from scheduling - methods such as :meth:`loop.call_soon` and :meth:`loop.call_later`; - -* The `Server Objects`_ section documents types returned from - event loop methods like :meth:`loop.create_server`; - -* The `Event Loop Implementations`_ section documents the - :class:`SelectorEventLoop` and :class:`ProactorEventLoop` classes; - -* The `Examples`_ section showcases how to work with some event - loop APIs. - - -.. _asyncio-event-loop: - -Event Loop Methods -================== - -Event loops have **low-level** APIs for the following: - -.. contents:: - :depth: 1 - :local: - - -Running and stopping the loop -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. method:: loop.run_until_complete(future) - - Run until the *future* (an instance of :class:`Future`) has - completed. - - If the argument is a :ref:`coroutine object ` it - is implicitly scheduled to run as a :class:`asyncio.Task`. - - Return the Future's result or raise its exception. - -.. method:: loop.run_forever() - - Run the event loop until :meth:`stop` is called. - - If :meth:`stop` is called before :meth:`run_forever()` is called, - the loop will poll the I/O selector once with a timeout of zero, - run all callbacks scheduled in response to I/O events (and - those that were already scheduled), and then exit. - - If :meth:`stop` is called while :meth:`run_forever` is running, - the loop will run the current batch of callbacks and then exit. - Note that new callbacks scheduled by callbacks will not run in this - case; instead, they will run the next time :meth:`run_forever` or - :meth:`run_until_complete` is called. - -.. method:: loop.stop() - - Stop the event loop. - -.. method:: loop.is_running() - - Return ``True`` if the event loop is currently running. - -.. method:: loop.is_closed() - - Return ``True`` if the event loop was closed. - -.. method:: loop.close() - - Close the event loop. - - The loop must not be running when this function is called. - Any pending callbacks will be discarded. - - This method clears all queues and shuts down the executor, but does - not wait for the executor to finish. - - This method is idempotent and irreversible. No other methods - should be called after the event loop is closed. - -.. coroutinemethod:: loop.shutdown_asyncgens() - - Schedule all currently open :term:`asynchronous generator` objects to - close with an :meth:`~agen.aclose()` call. After calling this method, - the event loop will issue a warning if a new asynchronous generator - is iterated. This should be used to reliably finalize all scheduled - asynchronous generators. - - Note that there is no need to call this function when - :func:`asyncio.run` is used. - - Example:: - - try: - loop.run_forever() - finally: - loop.run_until_complete(loop.shutdown_asyncgens()) - loop.close() - - .. versionadded:: 3.6 - -.. coroutinemethod:: loop.shutdown_default_executor() - - Schedule the closure of the default executor, but wait for the - :class:`ThreadPoolExecutor` to finish joining all of the threads. After - calling this method, a :exc:`RuntimeError` will be raised if - :meth:`loop.run_in_executor` is called while using the default executor. - - Note that there is no need to call this function when - :func:`asyncio.run` is used. - - .. versionadded:: 3.9 - - -Scheduling callbacks -^^^^^^^^^^^^^^^^^^^^ - -.. method:: loop.call_soon(callback, *args, context=None) - - Schedule a *callback* to be called with *args* arguments at - the next iteration of the event loop. - - Callbacks are called in the order in which they are registered. - Each callback will be called exactly once. - - An optional keyword-only *context* argument allows specifying a - custom :class:`contextvars.Context` for the *callback* to run in. - The current context is used when no *context* is provided. - - An instance of :class:`asyncio.Handle` is returned, which can be - used later to cancel the callback. - - This method is not thread-safe. - -.. method:: loop.call_soon_threadsafe(callback, *args, context=None) - - A thread-safe variant of :meth:`call_soon`. Must be used to - schedule callbacks *from another thread*. - - See the :ref:`concurrency and multithreading ` - section of the documentation. - -.. versionchanged:: 3.7 - The *context* keyword-only parameter was added. See :pep:`567` - for more details. - -.. _asyncio-pass-keywords: - -.. note:: - - Most :mod:`asyncio` scheduling functions don't allow passing - keyword arguments. To do that, use :func:`functools.partial`:: - - # will schedule "print("Hello", flush=True)" - loop.call_soon( - functools.partial(print, "Hello", flush=True)) - - Using partial objects is usually more convenient than using lambdas, - as asyncio can render partial objects better in debug and error - messages. - - -.. _asyncio-delayed-calls: - -Scheduling delayed callbacks -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Event loop provides mechanisms to schedule callback functions -to be called at some point in the future. Event loop uses monotonic -clocks to track time. - - -.. method:: loop.call_later(delay, callback, *args, context=None) - - Schedule *callback* to be called after the given *delay* - number of seconds (can be either an int or a float). - - An instance of :class:`asyncio.TimerHandle` is returned which can - be used to cancel the callback. - - *callback* will be called exactly once. If two callbacks are - scheduled for exactly the same time, the order in which they - are called is undefined. - - The optional positional *args* will be passed to the callback when - it is called. If you want the callback to be called with keyword - arguments use :func:`functools.partial`. - - An optional keyword-only *context* argument allows specifying a - custom :class:`contextvars.Context` for the *callback* to run in. - The current context is used when no *context* is provided. - - .. versionchanged:: 3.7 - The *context* keyword-only parameter was added. See :pep:`567` - for more details. - - .. versionchanged:: 3.8 - In Python 3.7 and earlier with the default event loop implementation, - the *delay* could not exceed one day. - This has been fixed in Python 3.8. - -.. method:: loop.call_at(when, callback, *args, context=None) - - Schedule *callback* to be called at the given absolute timestamp - *when* (an int or a float), using the same time reference as - :meth:`loop.time`. - - This method's behavior is the same as :meth:`call_later`. - - An instance of :class:`asyncio.TimerHandle` is returned which can - be used to cancel the callback. - - .. versionchanged:: 3.7 - The *context* keyword-only parameter was added. See :pep:`567` - for more details. - - .. versionchanged:: 3.8 - In Python 3.7 and earlier with the default event loop implementation, - the difference between *when* and the current time could not exceed - one day. This has been fixed in Python 3.8. - -.. method:: loop.time() - - Return the current time, as a :class:`float` value, according to - the event loop's internal monotonic clock. - -.. note:: - .. versionchanged:: 3.8 - In Python 3.7 and earlier timeouts (relative *delay* or absolute *when*) - should not exceed one day. This has been fixed in Python 3.8. - -.. seealso:: - - The :func:`asyncio.sleep` function. - - -Creating Futures and Tasks -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. method:: loop.create_future() - - Create an :class:`asyncio.Future` object attached to the event loop. - - This is the preferred way to create Futures in asyncio. This lets - third-party event loops provide alternative implementations of - the Future object (with better performance or instrumentation). - - .. versionadded:: 3.5.2 - -.. method:: loop.create_task(coro, \*, name=None) - - Schedule the execution of a :ref:`coroutine`. - Return a :class:`Task` object. - - Third-party event loops can use their own subclass of :class:`Task` - for interoperability. In this case, the result type is a subclass - of :class:`Task`. - - If the *name* argument is provided and not ``None``, it is set as - the name of the task using :meth:`Task.set_name`. - - .. versionchanged:: 3.8 - Added the ``name`` parameter. - -.. method:: loop.set_task_factory(factory) - - Set a task factory that will be used by - :meth:`loop.create_task`. - - If *factory* is ``None`` the default task factory will be set. - Otherwise, *factory* must be a *callable* with the signature matching - ``(loop, coro)``, where *loop* is a reference to the active - event loop, and *coro* is a coroutine object. The callable - must return a :class:`asyncio.Future`-compatible object. - -.. method:: loop.get_task_factory() - - Return a task factory or ``None`` if the default one is in use. - - -Opening network connections -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. coroutinemethod:: loop.create_connection(protocol_factory, \ - host=None, port=None, \*, ssl=None, \ - family=0, proto=0, flags=0, sock=None, \ - local_addr=None, server_hostname=None, \ - ssl_handshake_timeout=None) - - Open a streaming transport connection to a given - address specified by *host* and *port*. - - The socket family can be either :py:data:`~socket.AF_INET` or - :py:data:`~socket.AF_INET6` depending on *host* (or the *family* - argument, if provided). - - The socket type will be :py:data:`~socket.SOCK_STREAM`. - - *protocol_factory* must be a callable returning an - :ref:`asyncio protocol ` implementation. - - This method will try to establish the connection in the background. - When successful, it returns a ``(transport, protocol)`` pair. - - The chronological synopsis of the underlying operation is as follows: - - #. The connection is established and a :ref:`transport ` - is created for it. - - #. *protocol_factory* is called without arguments and is expected to - return a :ref:`protocol ` instance. - - #. The protocol instance is coupled with the transport by calling its - :meth:`~BaseProtocol.connection_made` method. - - #. A ``(transport, protocol)`` tuple is returned on success. - - The created transport is an implementation-dependent bidirectional - stream. - - Other arguments: - - * *ssl*: if given and not false, a SSL/TLS transport is created - (by default a plain TCP transport is created). If *ssl* is - a :class:`ssl.SSLContext` object, this context is used to create - the transport; if *ssl* is :const:`True`, a default context returned - from :func:`ssl.create_default_context` is used. - - .. seealso:: :ref:`SSL/TLS security considerations ` - - * *server_hostname* sets or overrides the hostname that the target - server's certificate will be matched against. Should only be passed - if *ssl* is not ``None``. By default the value of the *host* argument - is used. If *host* is empty, there is no default and you must pass a - value for *server_hostname*. If *server_hostname* is an empty - string, hostname matching is disabled (which is a serious security - risk, allowing for potential man-in-the-middle attacks). - - * *family*, *proto*, *flags* are the optional address family, protocol - and flags to be passed through to getaddrinfo() for *host* resolution. - If given, these should all be integers from the corresponding - :mod:`socket` module constants. - - * *happy_eyeballs_delay*, if given, enables Happy Eyeballs for this - connection. It should - be a floating-point number representing the amount of time in seconds - to wait for a connection attempt to complete, before starting the next - attempt in parallel. This is the "Connection Attempt Delay" as defined - in :rfc:`8305`. A sensible default value recommended by the RFC is ``0.25`` - (250 milliseconds). - - * *interleave* controls address reordering when a host name resolves to - multiple IP addresses. - If ``0`` or unspecified, no reordering is done, and addresses are - tried in the order returned by :meth:`getaddrinfo`. If a positive integer - is specified, the addresses are interleaved by address family, and the - given integer is interpreted as "First Address Family Count" as defined - in :rfc:`8305`. The default is ``0`` if *happy_eyeballs_delay* is not - specified, and ``1`` if it is. - - * *sock*, if given, should be an existing, already connected - :class:`socket.socket` object to be used by the transport. - If *sock* is given, none of *host*, *port*, *family*, *proto*, *flags*, - *happy_eyeballs_delay*, *interleave* - and *local_addr* should be specified. - - * *local_addr*, if given, is a ``(local_host, local_port)`` tuple used - to bind the socket to locally. The *local_host* and *local_port* - are looked up using ``getaddrinfo()``, similarly to *host* and *port*. - - * *ssl_handshake_timeout* is (for a TLS connection) the time in seconds - to wait for the TLS handshake to complete before aborting the connection. - ``60.0`` seconds if ``None`` (default). - - .. versionadded:: 3.8 - - The *happy_eyeballs_delay* and *interleave* parameters. - - .. versionadded:: 3.7 - - The *ssl_handshake_timeout* parameter. - - .. versionchanged:: 3.6 - - The socket option :py:data:`~socket.TCP_NODELAY` is set by default - for all TCP connections. - - .. versionchanged:: 3.5 - - Added support for SSL/TLS in :class:`ProactorEventLoop`. - - .. seealso:: - - The :func:`open_connection` function is a high-level alternative - API. It returns a pair of (:class:`StreamReader`, :class:`StreamWriter`) - that can be used directly in async/await code. - -.. coroutinemethod:: loop.create_datagram_endpoint(protocol_factory, \ - local_addr=None, remote_addr=None, \*, \ - family=0, proto=0, flags=0, \ - reuse_address=None, reuse_port=None, \ - allow_broadcast=None, sock=None) - - Create a datagram connection. - - The socket family can be either :py:data:`~socket.AF_INET`, - :py:data:`~socket.AF_INET6`, or :py:data:`~socket.AF_UNIX`, - depending on *host* (or the *family* argument, if provided). - - The socket type will be :py:data:`~socket.SOCK_DGRAM`. - - *protocol_factory* must be a callable returning a - :ref:`protocol ` implementation. - - A tuple of ``(transport, protocol)`` is returned on success. - - Other arguments: - - * *local_addr*, if given, is a ``(local_host, local_port)`` tuple used - to bind the socket to locally. The *local_host* and *local_port* - are looked up using :meth:`getaddrinfo`. - - * *remote_addr*, if given, is a ``(remote_host, remote_port)`` tuple used - to connect the socket to a remote address. The *remote_host* and - *remote_port* are looked up using :meth:`getaddrinfo`. - - * *family*, *proto*, *flags* are the optional address family, protocol - and flags to be passed through to :meth:`getaddrinfo` for *host* - resolution. If given, these should all be integers from the - corresponding :mod:`socket` module constants. - - * *reuse_address* tells the kernel to reuse a local socket in - ``TIME_WAIT`` state, without waiting for its natural timeout to - expire. If not specified will automatically be set to ``True`` on - Unix. - - * *reuse_port* tells the kernel to allow this endpoint to be bound to the - same port as other existing endpoints are bound to, so long as they all - set this flag when being created. This option is not supported on Windows - and some Unixes. If the :py:data:`~socket.SO_REUSEPORT` constant is not - defined then this capability is unsupported. - - * *allow_broadcast* tells the kernel to allow this endpoint to send - messages to the broadcast address. - - * *sock* can optionally be specified in order to use a preexisting, - already connected, :class:`socket.socket` object to be used by the - transport. If specified, *local_addr* and *remote_addr* should be omitted - (must be :const:`None`). - - See :ref:`UDP echo client protocol ` and - :ref:`UDP echo server protocol ` examples. - - .. versionchanged:: 3.4.4 - The *family*, *proto*, *flags*, *reuse_address*, *reuse_port, - *allow_broadcast*, and *sock* parameters were added. - - .. versionchanged:: 3.8 - Added support for Windows. - -.. coroutinemethod:: loop.create_unix_connection(protocol_factory, \ - path=None, \*, ssl=None, sock=None, \ - server_hostname=None, ssl_handshake_timeout=None) - - Create a Unix connection. - - The socket family will be :py:data:`~socket.AF_UNIX`; socket - type will be :py:data:`~socket.SOCK_STREAM`. - - A tuple of ``(transport, protocol)`` is returned on success. - - *path* is the name of a Unix domain socket and is required, - unless a *sock* parameter is specified. Abstract Unix sockets, - :class:`str`, :class:`bytes`, and :class:`~pathlib.Path` paths are - supported. - - See the documentation of the :meth:`loop.create_connection` method - for information about arguments to this method. - - .. availability:: Unix. - - .. versionadded:: 3.7 - - The *ssl_handshake_timeout* parameter. - - .. versionchanged:: 3.7 - - The *path* parameter can now be a :term:`path-like object`. - - -Creating network servers -^^^^^^^^^^^^^^^^^^^^^^^^ - -.. coroutinemethod:: loop.create_server(protocol_factory, \ - host=None, port=None, \*, \ - family=socket.AF_UNSPEC, \ - flags=socket.AI_PASSIVE, \ - sock=None, backlog=100, ssl=None, \ - reuse_address=None, reuse_port=None, \ - ssl_handshake_timeout=None, start_serving=True) - - Create a TCP server (socket type :data:`~socket.SOCK_STREAM`) listening - on *port* of the *host* address. - - Returns a :class:`Server` object. - - Arguments: - - * *protocol_factory* must be a callable returning a - :ref:`protocol ` implementation. - - * The *host* parameter can be set to several types which determine where - the server would be listening: - - - If *host* is a string, the TCP server is bound to a single network - interface specified by *host*. - - - If *host* is a sequence of strings, the TCP server is bound to all - network interfaces specified by the sequence. - - - If *host* is an empty string or ``None``, all interfaces are - assumed and a list of multiple sockets will be returned (most likely - one for IPv4 and another one for IPv6). - - * *family* can be set to either :data:`socket.AF_INET` or - :data:`~socket.AF_INET6` to force the socket to use IPv4 or IPv6. - If not set, the *family* will be determined from host name - (defaults to :data:`~socket.AF_UNSPEC`). - - * *flags* is a bitmask for :meth:`getaddrinfo`. - - * *sock* can optionally be specified in order to use a preexisting - socket object. If specified, *host* and *port* must not be specified. - - * *backlog* is the maximum number of queued connections passed to - :meth:`~socket.socket.listen` (defaults to 100). - - * *ssl* can be set to an :class:`~ssl.SSLContext` instance to enable - TLS over the accepted connections. - - * *reuse_address* tells the kernel to reuse a local socket in - ``TIME_WAIT`` state, without waiting for its natural timeout to - expire. If not specified will automatically be set to ``True`` on - Unix. - - * *reuse_port* tells the kernel to allow this endpoint to be bound to the - same port as other existing endpoints are bound to, so long as they all - set this flag when being created. This option is not supported on - Windows. - - * *ssl_handshake_timeout* is (for a TLS server) the time in seconds to wait - for the TLS handshake to complete before aborting the connection. - ``60.0`` seconds if ``None`` (default). - - * *start_serving* set to ``True`` (the default) causes the created server - to start accepting connections immediately. When set to ``False``, - the user should await on :meth:`Server.start_serving` or - :meth:`Server.serve_forever` to make the server to start accepting - connections. - - .. versionadded:: 3.7 - - Added *ssl_handshake_timeout* and *start_serving* parameters. - - .. versionchanged:: 3.6 - - The socket option :py:data:`~socket.TCP_NODELAY` is set by default - for all TCP connections. - - .. versionchanged:: 3.5 - - Added support for SSL/TLS in :class:`ProactorEventLoop`. - - .. versionchanged:: 3.5.1 - - The *host* parameter can be a sequence of strings. - - .. seealso:: - - The :func:`start_server` function is a higher-level alternative API - that returns a pair of :class:`StreamReader` and :class:`StreamWriter` - that can be used in an async/await code. - - -.. coroutinemethod:: loop.create_unix_server(protocol_factory, path=None, \ - \*, sock=None, backlog=100, ssl=None, \ - ssl_handshake_timeout=None, start_serving=True) - - Similar to :meth:`loop.create_server` but works with the - :py:data:`~socket.AF_UNIX` socket family. - - *path* is the name of a Unix domain socket, and is required, - unless a *sock* argument is provided. Abstract Unix sockets, - :class:`str`, :class:`bytes`, and :class:`~pathlib.Path` paths - are supported. - - See the documentation of the :meth:`loop.create_server` method - for information about arguments to this method. - - .. availability:: Unix. - - .. versionadded:: 3.7 - - The *ssl_handshake_timeout* and *start_serving* parameters. - - .. versionchanged:: 3.7 - - The *path* parameter can now be a :class:`~pathlib.Path` object. - -.. coroutinemethod:: loop.connect_accepted_socket(protocol_factory, \ - sock, \*, ssl=None, ssl_handshake_timeout=None) - - Wrap an already accepted connection into a transport/protocol pair. - - This method can be used by servers that accept connections outside - of asyncio but that use asyncio to handle them. - - Parameters: - - * *protocol_factory* must be a callable returning a - :ref:`protocol ` implementation. - - * *sock* is a preexisting socket object returned from - :meth:`socket.accept `. - - * *ssl* can be set to an :class:`~ssl.SSLContext` to enable SSL over - the accepted connections. - - * *ssl_handshake_timeout* is (for an SSL connection) the time in seconds to - wait for the SSL handshake to complete before aborting the connection. - ``60.0`` seconds if ``None`` (default). - - Returns a ``(transport, protocol)`` pair. - - .. versionadded:: 3.7 - - The *ssl_handshake_timeout* parameter. - - .. versionadded:: 3.5.3 - - -Transferring files -^^^^^^^^^^^^^^^^^^ - -.. coroutinemethod:: loop.sendfile(transport, file, \ - offset=0, count=None, *, fallback=True) - - Send a *file* over a *transport*. Return the total number of bytes - sent. - - The method uses high-performance :meth:`os.sendfile` if available. - - *file* must be a regular file object opened in binary mode. - - *offset* tells from where to start reading the file. If specified, - *count* is the total number of bytes to transmit as opposed to - sending the file until EOF is reached. File position is always updated, - even when this method raises an error, and - :meth:`file.tell() ` can be used to obtain the actual - number of bytes sent. - - *fallback* set to ``True`` makes asyncio to manually read and send - the file when the platform does not support the sendfile system call - (e.g. Windows or SSL socket on Unix). - - Raise :exc:`SendfileNotAvailableError` if the system does not support - the *sendfile* syscall and *fallback* is ``False``. - - .. versionadded:: 3.7 - - -TLS Upgrade -^^^^^^^^^^^ - -.. coroutinemethod:: loop.start_tls(transport, protocol, \ - sslcontext, \*, server_side=False, \ - server_hostname=None, ssl_handshake_timeout=None) - - Upgrade an existing transport-based connection to TLS. - - Return a new transport instance, that the *protocol* must start using - immediately after the *await*. The *transport* instance passed to - the *start_tls* method should never be used again. - - Parameters: - - * *transport* and *protocol* instances that methods like - :meth:`~loop.create_server` and - :meth:`~loop.create_connection` return. - - * *sslcontext*: a configured instance of :class:`~ssl.SSLContext`. - - * *server_side* pass ``True`` when a server-side connection is being - upgraded (like the one created by :meth:`~loop.create_server`). - - * *server_hostname*: sets or overrides the host name that the target - server's certificate will be matched against. - - * *ssl_handshake_timeout* is (for a TLS connection) the time in seconds to - wait for the TLS handshake to complete before aborting the connection. - ``60.0`` seconds if ``None`` (default). - - .. versionadded:: 3.7 - - -Watching file descriptors -^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. method:: loop.add_reader(fd, callback, \*args) - - Start monitoring the *fd* file descriptor for read availability and - invoke *callback* with the specified arguments once *fd* is available for - reading. - -.. method:: loop.remove_reader(fd) - - Stop monitoring the *fd* file descriptor for read availability. - -.. method:: loop.add_writer(fd, callback, \*args) - - Start monitoring the *fd* file descriptor for write availability and - invoke *callback* with the specified arguments once *fd* is available for - writing. - - Use :func:`functools.partial` :ref:`to pass keyword arguments - ` to *callback*. - -.. method:: loop.remove_writer(fd) - - Stop monitoring the *fd* file descriptor for write availability. - -See also :ref:`Platform Support ` section -for some limitations of these methods. - - -Working with socket objects directly -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In general, protocol implementations that use transport-based APIs -such as :meth:`loop.create_connection` and :meth:`loop.create_server` -are faster than implementations that work with sockets directly. -However, there are some use cases when performance is not critical, and -working with :class:`~socket.socket` objects directly is more -convenient. - -.. coroutinemethod:: loop.sock_recv(sock, nbytes) - - Receive up to *nbytes* from *sock*. Asynchronous version of - :meth:`socket.recv() `. - - Return the received data as a bytes object. - - *sock* must be a non-blocking socket. - - .. versionchanged:: 3.7 - Even though this method was always documented as a coroutine - method, releases before Python 3.7 returned a :class:`Future`. - Since Python 3.7 this is an ``async def`` method. - -.. coroutinemethod:: loop.sock_recv_into(sock, buf) - - Receive data from *sock* into the *buf* buffer. Modeled after the blocking - :meth:`socket.recv_into() ` method. - - Return the number of bytes written to the buffer. - - *sock* must be a non-blocking socket. - - .. versionadded:: 3.7 - -.. coroutinemethod:: loop.sock_sendall(sock, data) - - Send *data* to the *sock* socket. Asynchronous version of - :meth:`socket.sendall() `. - - This method continues to send to the socket until either all data - in *data* has been sent or an error occurs. ``None`` is returned - on success. On error, an exception is raised. Additionally, there is no way - to determine how much data, if any, was successfully processed by the - receiving end of the connection. - - *sock* must be a non-blocking socket. - - .. versionchanged:: 3.7 - Even though the method was always documented as a coroutine - method, before Python 3.7 it returned an :class:`Future`. - Since Python 3.7, this is an ``async def`` method. - -.. coroutinemethod:: loop.sock_connect(sock, address) - - Connect *sock* to a remote socket at *address*. - - Asynchronous version of :meth:`socket.connect() `. - - *sock* must be a non-blocking socket. - - .. versionchanged:: 3.5.2 - ``address`` no longer needs to be resolved. ``sock_connect`` - will try to check if the *address* is already resolved by calling - :func:`socket.inet_pton`. If not, - :meth:`loop.getaddrinfo` will be used to resolve the - *address*. - - .. seealso:: - - :meth:`loop.create_connection` - and :func:`asyncio.open_connection() `. - - -.. coroutinemethod:: loop.sock_accept(sock) - - Accept a connection. Modeled after the blocking - :meth:`socket.accept() ` method. - - The socket must be bound to an address and listening - for connections. The return value is a pair ``(conn, address)`` where *conn* - is a *new* socket object usable to send and receive data on the connection, - and *address* is the address bound to the socket on the other end of the - connection. - - *sock* must be a non-blocking socket. - - .. versionchanged:: 3.7 - Even though the method was always documented as a coroutine - method, before Python 3.7 it returned a :class:`Future`. - Since Python 3.7, this is an ``async def`` method. - - .. seealso:: - - :meth:`loop.create_server` and :func:`start_server`. - -.. coroutinemethod:: loop.sock_sendfile(sock, file, offset=0, count=None, \ - \*, fallback=True) - - Send a file using high-performance :mod:`os.sendfile` if possible. - Return the total number of bytes sent. - - Asynchronous version of :meth:`socket.sendfile() `. - - *sock* must be a non-blocking :const:`socket.SOCK_STREAM` - :class:`~socket.socket`. - - *file* must be a regular file object open in binary mode. - - *offset* tells from where to start reading the file. If specified, - *count* is the total number of bytes to transmit as opposed to - sending the file until EOF is reached. File position is always updated, - even when this method raises an error, and - :meth:`file.tell() ` can be used to obtain the actual - number of bytes sent. - - *fallback*, when set to ``True``, makes asyncio manually read and send - the file when the platform does not support the sendfile syscall - (e.g. Windows or SSL socket on Unix). - - Raise :exc:`SendfileNotAvailableError` if the system does not support - *sendfile* syscall and *fallback* is ``False``. - - *sock* must be a non-blocking socket. - - .. versionadded:: 3.7 - - -DNS -^^^ - -.. coroutinemethod:: loop.getaddrinfo(host, port, \*, family=0, \ - type=0, proto=0, flags=0) - - Asynchronous version of :meth:`socket.getaddrinfo`. - -.. coroutinemethod:: loop.getnameinfo(sockaddr, flags=0) - - Asynchronous version of :meth:`socket.getnameinfo`. - -.. versionchanged:: 3.7 - Both *getaddrinfo* and *getnameinfo* methods were always documented - to return a coroutine, but prior to Python 3.7 they were, in fact, - returning :class:`asyncio.Future` objects. Starting with Python 3.7 - both methods are coroutines. - - -Working with pipes -^^^^^^^^^^^^^^^^^^ - -.. coroutinemethod:: loop.connect_read_pipe(protocol_factory, pipe) - - Register the read end of *pipe* in the event loop. - - *protocol_factory* must be a callable returning an - :ref:`asyncio protocol ` implementation. - - *pipe* is a :term:`file-like object `. - - Return pair ``(transport, protocol)``, where *transport* supports - the :class:`ReadTransport` interface and *protocol* is an object - instantiated by the *protocol_factory*. - - With :class:`SelectorEventLoop` event loop, the *pipe* is set to - non-blocking mode. - -.. coroutinemethod:: loop.connect_write_pipe(protocol_factory, pipe) - - Register the write end of *pipe* in the event loop. - - *protocol_factory* must be a callable returning an - :ref:`asyncio protocol ` implementation. - - *pipe* is :term:`file-like object `. - - Return pair ``(transport, protocol)``, where *transport* supports - :class:`WriteTransport` interface and *protocol* is an object - instantiated by the *protocol_factory*. - - With :class:`SelectorEventLoop` event loop, the *pipe* is set to - non-blocking mode. - -.. note:: - - :class:`SelectorEventLoop` does not support the above methods on - Windows. Use :class:`ProactorEventLoop` instead for Windows. - -.. seealso:: - - The :meth:`loop.subprocess_exec` and - :meth:`loop.subprocess_shell` methods. - - -Unix signals -^^^^^^^^^^^^ - -.. method:: loop.add_signal_handler(signum, callback, \*args) - - Set *callback* as the handler for the *signum* signal. - - The callback will be invoked by *loop*, along with other queued callbacks - and runnable coroutines of that event loop. Unlike signal handlers - registered using :func:`signal.signal`, a callback registered with this - function is allowed to interact with the event loop. - - Raise :exc:`ValueError` if the signal number is invalid or uncatchable. - Raise :exc:`RuntimeError` if there is a problem setting up the handler. - - Use :func:`functools.partial` :ref:`to pass keyword arguments - ` to *callback*. - - Like :func:`signal.signal`, this function must be invoked in the main - thread. - -.. method:: loop.remove_signal_handler(sig) - - Remove the handler for the *sig* signal. - - Return ``True`` if the signal handler was removed, or ``False`` if - no handler was set for the given signal. - - .. availability:: Unix. - -.. seealso:: - - The :mod:`signal` module. - - -Executing code in thread or process pools -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. awaitablemethod:: loop.run_in_executor(executor, func, \*args) - - Arrange for *func* to be called in the specified executor. - - The *executor* argument should be an :class:`concurrent.futures.Executor` - instance. The default executor is used if *executor* is ``None``. - - Example:: - - import asyncio - import concurrent.futures - - def blocking_io(): - # File operations (such as logging) can block the - # event loop: run them in a thread pool. - with open('/dev/urandom', 'rb') as f: - return f.read(100) - - def cpu_bound(): - # CPU-bound operations will block the event loop: - # in general it is preferable to run them in a - # process pool. - return sum(i * i for i in range(10 ** 7)) - - async def main(): - loop = asyncio.get_running_loop() - - ## Options: - - # 1. Run in the default loop's executor: - result = await loop.run_in_executor( - None, blocking_io) - print('default thread pool', result) - - # 2. Run in a custom thread pool: - with concurrent.futures.ThreadPoolExecutor() as pool: - result = await loop.run_in_executor( - pool, blocking_io) - print('custom thread pool', result) - - # 3. Run in a custom process pool: - with concurrent.futures.ProcessPoolExecutor() as pool: - result = await loop.run_in_executor( - pool, cpu_bound) - print('custom process pool', result) - - asyncio.run(main()) - - This method returns a :class:`asyncio.Future` object. - - Use :func:`functools.partial` :ref:`to pass keyword arguments - ` to *func*. - - .. versionchanged:: 3.5.3 - :meth:`loop.run_in_executor` no longer configures the - ``max_workers`` of the thread pool executor it creates, instead - leaving it up to the thread pool executor - (:class:`~concurrent.futures.ThreadPoolExecutor`) to set the - default. - -.. method:: loop.set_default_executor(executor) - - Set *executor* as the default executor used by :meth:`run_in_executor`. - *executor* should be an instance of - :class:`~concurrent.futures.ThreadPoolExecutor`. - - .. deprecated:: 3.8 - Using an executor that is not an instance of - :class:`~concurrent.futures.ThreadPoolExecutor` is deprecated and - will trigger an error in Python 3.9. - - *executor* must be an instance of - :class:`concurrent.futures.ThreadPoolExecutor`. - - -Error Handling API -^^^^^^^^^^^^^^^^^^ - -Allows customizing how exceptions are handled in the event loop. - -.. method:: loop.set_exception_handler(handler) - - Set *handler* as the new event loop exception handler. - - If *handler* is ``None``, the default exception handler will - be set. Otherwise, *handler* must be a callable with the signature - matching ``(loop, context)``, where ``loop`` - is a reference to the active event loop, and ``context`` - is a ``dict`` object containing the details of the exception - (see :meth:`call_exception_handler` documentation for details - about context). - -.. method:: loop.get_exception_handler() - - Return the current exception handler, or ``None`` if no custom - exception handler was set. - - .. versionadded:: 3.5.2 - -.. method:: loop.default_exception_handler(context) - - Default exception handler. - - This is called when an exception occurs and no exception - handler is set. This can be called by a custom exception - handler that wants to defer to the default handler behavior. - - *context* parameter has the same meaning as in - :meth:`call_exception_handler`. - -.. method:: loop.call_exception_handler(context) - - Call the current event loop exception handler. - - *context* is a ``dict`` object containing the following keys - (new keys may be introduced in future Python versions): - - * 'message': Error message; - * 'exception' (optional): Exception object; - * 'future' (optional): :class:`asyncio.Future` instance; - * 'handle' (optional): :class:`asyncio.Handle` instance; - * 'protocol' (optional): :ref:`Protocol ` instance; - * 'transport' (optional): :ref:`Transport ` instance; - * 'socket' (optional): :class:`socket.socket` instance. - - .. note:: - - This method should not be overloaded in subclassed - event loops. For custom exception handling, use - the :meth:`set_exception_handler()` method. - -Enabling debug mode -^^^^^^^^^^^^^^^^^^^ - -.. method:: loop.get_debug() - - Get the debug mode (:class:`bool`) of the event loop. - - The default value is ``True`` if the environment variable - :envvar:`PYTHONASYNCIODEBUG` is set to a non-empty string, ``False`` - otherwise. - -.. method:: loop.set_debug(enabled: bool) - - Set the debug mode of the event loop. - - .. versionchanged:: 3.7 - - The new ``-X dev`` command line option can now also be used - to enable the debug mode. - -.. seealso:: - - The :ref:`debug mode of asyncio `. - - -Running Subprocesses -^^^^^^^^^^^^^^^^^^^^ - -Methods described in this subsections are low-level. In regular -async/await code consider using the high-level -:func:`asyncio.create_subprocess_shell` and -:func:`asyncio.create_subprocess_exec` convenience functions instead. - -.. note:: - - The default asyncio event loop on **Windows** does not support - subprocesses. See :ref:`Subprocess Support on Windows - ` for details. - -.. coroutinemethod:: loop.subprocess_exec(protocol_factory, \*args, \ - stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ - stderr=subprocess.PIPE, \*\*kwargs) - - Create a subprocess from one or more string arguments specified by - *args*. - - *args* must be a list of strings represented by: - - * :class:`str`; - * or :class:`bytes`, encoded to the - :ref:`filesystem encoding `. - - The first string specifies the program executable, - and the remaining strings specify the arguments. Together, string - arguments form the ``argv`` of the program. - - This is similar to the standard library :class:`subprocess.Popen` - class called with ``shell=False`` and the list of strings passed as - the first argument; however, where :class:`~subprocess.Popen` takes - a single argument which is list of strings, *subprocess_exec* - takes multiple string arguments. - - The *protocol_factory* must be a callable returning a subclass of the - :class:`asyncio.SubprocessProtocol` class. - - Other parameters: - - * *stdin* can be any of these: - - * a file-like object representing a pipe to be connected to the - subprocess's standard input stream using - :meth:`~loop.connect_write_pipe` - * the :const:`subprocess.PIPE` constant (default) which will create a new - pipe and connect it, - * the value ``None`` which will make the subprocess inherit the file - descriptor from this process - * the :const:`subprocess.DEVNULL` constant which indicates that the - special :data:`os.devnull` file will be used - - * *stdout* can be any of these: - - * a file-like object representing a pipe to be connected to the - subprocess's standard output stream using - :meth:`~loop.connect_write_pipe` - * the :const:`subprocess.PIPE` constant (default) which will create a new - pipe and connect it, - * the value ``None`` which will make the subprocess inherit the file - descriptor from this process - * the :const:`subprocess.DEVNULL` constant which indicates that the - special :data:`os.devnull` file will be used - - * *stderr* can be any of these: - - * a file-like object representing a pipe to be connected to the - subprocess's standard error stream using - :meth:`~loop.connect_write_pipe` - * the :const:`subprocess.PIPE` constant (default) which will create a new - pipe and connect it, - * the value ``None`` which will make the subprocess inherit the file - descriptor from this process - * the :const:`subprocess.DEVNULL` constant which indicates that the - special :data:`os.devnull` file will be used - * the :const:`subprocess.STDOUT` constant which will connect the standard - error stream to the process' standard output stream - - * All other keyword arguments are passed to :class:`subprocess.Popen` - without interpretation, except for *bufsize*, *universal_newlines*, - *shell*, *text*, *encoding* and *errors*, which should not be specified - at all. - - The ``asyncio`` subprocess API does not support decoding the streams - as text. :func:`bytes.decode` can be used to convert the bytes returned - from the stream to text. - - See the constructor of the :class:`subprocess.Popen` class - for documentation on other arguments. - - Returns a pair of ``(transport, protocol)``, where *transport* - conforms to the :class:`asyncio.SubprocessTransport` base class and - *protocol* is an object instantiated by the *protocol_factory*. - -.. coroutinemethod:: loop.subprocess_shell(protocol_factory, cmd, \*, \ - stdin=subprocess.PIPE, stdout=subprocess.PIPE, \ - stderr=subprocess.PIPE, \*\*kwargs) - - Create a subprocess from *cmd*, which can be a :class:`str` or a - :class:`bytes` string encoded to the - :ref:`filesystem encoding `, - using the platform's "shell" syntax. - - This is similar to the standard library :class:`subprocess.Popen` - class called with ``shell=True``. - - The *protocol_factory* must be a callable returning a subclass of the - :class:`SubprocessProtocol` class. - - See :meth:`~loop.subprocess_exec` for more details about - the remaining arguments. - - Returns a pair of ``(transport, protocol)``, where *transport* - conforms to the :class:`SubprocessTransport` base class and - *protocol* is an object instantiated by the *protocol_factory*. - -.. note:: - It is the application's responsibility to ensure that all whitespace - and special characters are quoted appropriately to avoid `shell injection - `_ - vulnerabilities. The :func:`shlex.quote` function can be used to - properly escape whitespace and special characters in strings that - are going to be used to construct shell commands. - - -Callback Handles -================ - -.. class:: Handle - - A callback wrapper object returned by :meth:`loop.call_soon`, - :meth:`loop.call_soon_threadsafe`. - - .. method:: cancel() - - Cancel the callback. If the callback has already been canceled - or executed, this method has no effect. - - .. method:: cancelled() - - Return ``True`` if the callback was cancelled. - - .. versionadded:: 3.7 - -.. class:: TimerHandle - - A callback wrapper object returned by :meth:`loop.call_later`, - and :meth:`loop.call_at`. - - This class is a subclass of :class:`Handle`. - - .. method:: when() - - Return a scheduled callback time as :class:`float` seconds. - - The time is an absolute timestamp, using the same time - reference as :meth:`loop.time`. - - .. versionadded:: 3.7 - - -Server Objects -============== - -Server objects are created by :meth:`loop.create_server`, -:meth:`loop.create_unix_server`, :func:`start_server`, -and :func:`start_unix_server` functions. - -Do not instantiate the class directly. - -.. class:: Server - - *Server* objects are asynchronous context managers. When used in an - ``async with`` statement, it's guaranteed that the Server object is - closed and not accepting new connections when the ``async with`` - statement is completed:: - - srv = await loop.create_server(...) - - async with srv: - # some code - - # At this point, srv is closed and no longer accepts new connections. - - - .. versionchanged:: 3.7 - Server object is an asynchronous context manager since Python 3.7. - - .. method:: close() - - Stop serving: close listening sockets and set the :attr:`sockets` - attribute to ``None``. - - The sockets that represent existing incoming client connections - are left open. - - The server is closed asynchronously, use the :meth:`wait_closed` - coroutine to wait until the server is closed. - - .. method:: get_loop() - - Return the event loop associated with the server object. - - .. versionadded:: 3.7 - - .. coroutinemethod:: start_serving() - - Start accepting connections. - - This method is idempotent, so it can be called when - the server is already being serving. - - The *start_serving* keyword-only parameter to - :meth:`loop.create_server` and - :meth:`asyncio.start_server` allows creating a Server object - that is not accepting connections initially. In this case - ``Server.start_serving()``, or :meth:`Server.serve_forever` can be used - to make the Server start accepting connections. - - .. versionadded:: 3.7 - - .. coroutinemethod:: serve_forever() - - Start accepting connections until the coroutine is cancelled. - Cancellation of ``serve_forever`` task causes the server - to be closed. - - This method can be called if the server is already accepting - connections. Only one ``serve_forever`` task can exist per - one *Server* object. - - Example:: - - async def client_connected(reader, writer): - # Communicate with the client with - # reader/writer streams. For example: - await reader.readline() - - async def main(host, port): - srv = await asyncio.start_server( - client_connected, host, port) - await srv.serve_forever() - - asyncio.run(main('127.0.0.1', 0)) - - .. versionadded:: 3.7 - - .. method:: is_serving() - - Return ``True`` if the server is accepting new connections. - - .. versionadded:: 3.7 - - .. coroutinemethod:: wait_closed() - - Wait until the :meth:`close` method completes. - - .. attribute:: sockets - - List of :class:`socket.socket` objects the server is listening on. - - .. versionchanged:: 3.7 - Prior to Python 3.7 ``Server.sockets`` used to return an - internal list of server sockets directly. In 3.7 a copy - of that list is returned. - - -.. _asyncio-event-loops: - -Event Loop Implementations -========================== - -asyncio ships with two different event loop implementations: -:class:`SelectorEventLoop` and :class:`ProactorEventLoop`. - -By default asyncio is configured to use :class:`SelectorEventLoop` -on Unix and :class:`ProactorEventLoop` on Windows. - - -.. class:: SelectorEventLoop - - An event loop based on the :mod:`selectors` module. - - Uses the most efficient *selector* available for the given - platform. It is also possible to manually configure the - exact selector implementation to be used:: - - import asyncio - import selectors - - selector = selectors.SelectSelector() - loop = asyncio.SelectorEventLoop(selector) - asyncio.set_event_loop(loop) - - - .. availability:: Unix, Windows. - - -.. class:: ProactorEventLoop - - An event loop for Windows that uses "I/O Completion Ports" (IOCP). - - .. availability:: Windows. - - .. seealso:: - - `MSDN documentation on I/O Completion Ports - `_. - - -.. class:: AbstractEventLoop - - Abstract base class for asyncio-compliant event loops. - - The :ref:`Event Loop Methods ` section lists all - methods that an alternative implementation of ``AbstractEventLoop`` - should have defined. - - -Examples -======== - -Note that all examples in this section **purposefully** show how -to use the low-level event loop APIs, such as :meth:`loop.run_forever` -and :meth:`loop.call_soon`. Modern asyncio applications rarely -need to be written this way; consider using the high-level functions -like :func:`asyncio.run`. - - -.. _asyncio_example_lowlevel_helloworld: - -Hello World with call_soon() -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -An example using the :meth:`loop.call_soon` method to schedule a -callback. The callback displays ``"Hello World"`` and then stops the -event loop:: - - import asyncio - - def hello_world(loop): - """A callback to print 'Hello World' and stop the event loop""" - print('Hello World') - loop.stop() - - loop = asyncio.get_event_loop() - - # Schedule a call to hello_world() - loop.call_soon(hello_world, loop) - - # Blocking call interrupted by loop.stop() - try: - loop.run_forever() - finally: - loop.close() - -.. seealso:: - - A similar :ref:`Hello World ` - example created with a coroutine and the :func:`run` function. - - -.. _asyncio_example_call_later: - -Display the current date with call_later() -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -An example of a callback displaying the current date every second. The -callback uses the :meth:`loop.call_later` method to reschedule itself -after 5 seconds, and then stops the event loop:: - - import asyncio - import datetime - - def display_date(end_time, loop): - print(datetime.datetime.now()) - if (loop.time() + 1.0) < end_time: - loop.call_later(1, display_date, end_time, loop) - else: - loop.stop() - - loop = asyncio.get_event_loop() - - # Schedule the first call to display_date() - end_time = loop.time() + 5.0 - loop.call_soon(display_date, end_time, loop) - - # Blocking call interrupted by loop.stop() - try: - loop.run_forever() - finally: - loop.close() - -.. seealso:: - - A similar :ref:`current date ` example - created with a coroutine and the :func:`run` function. - - -.. _asyncio_example_watch_fd: - -Watch a file descriptor for read events -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Wait until a file descriptor received some data using the -:meth:`loop.add_reader` method and then close the event loop:: - - import asyncio - from socket import socketpair - - # Create a pair of connected file descriptors - rsock, wsock = socketpair() - - loop = asyncio.get_event_loop() - - def reader(): - data = rsock.recv(100) - print("Received:", data.decode()) - - # We are done: unregister the file descriptor - loop.remove_reader(rsock) - - # Stop the event loop - loop.stop() - - # Register the file descriptor for read event - loop.add_reader(rsock, reader) - - # Simulate the reception of data from the network - loop.call_soon(wsock.send, 'abc'.encode()) - - try: - # Run the event loop - loop.run_forever() - finally: - # We are done. Close sockets and the event loop. - rsock.close() - wsock.close() - loop.close() - -.. seealso:: - - * A similar :ref:`example ` - using transports, protocols, and the - :meth:`loop.create_connection` method. - - * Another similar :ref:`example ` - using the high-level :func:`asyncio.connect` function and streams. - - -.. _asyncio_example_unix_signals: - -Set signal handlers for SIGINT and SIGTERM -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -(This ``signals`` example only works on Unix.) - -Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM` -using the :meth:`loop.add_signal_handler` method:: - - import asyncio - import functools - import os - import signal - - def ask_exit(signame, loop): - print("got signal %s: exit" % signame) - loop.stop() - - async def main(): - loop = asyncio.get_running_loop() - - for signame in {'SIGINT', 'SIGTERM'}: - loop.add_signal_handler( - getattr(signal, signame), - functools.partial(ask_exit, signame, loop)) - - await asyncio.sleep(3600) - - print("Event loop running for 1 hour, press Ctrl+C to interrupt.") - print(f"pid {os.getpid()}: send SIGINT or SIGTERM to exit.") - - asyncio.run(main()) From 260cace386c5ecef1e82a9a11c91e7c60b0f60c5 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2019 21:38:43 +0000 Subject: [PATCH 22/26] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2019-09-11-21-38-41.bpo-34037.LIAS_3.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2019-09-11-21-38-41.bpo-34037.LIAS_3.rst diff --git a/Misc/NEWS.d/next/Library/2019-09-11-21-38-41.bpo-34037.LIAS_3.rst b/Misc/NEWS.d/next/Library/2019-09-11-21-38-41.bpo-34037.LIAS_3.rst new file mode 100644 index 00000000000000..2e15cbd12bf734 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-09-11-21-38-41.bpo-34037.LIAS_3.rst @@ -0,0 +1,4 @@ +For :mod:`asyncio`, add a new coroutine :meth:`loop.shutdown_default_executor`. +The new coroutine provides an API to schedule an executor shutdown that waits +on the threadpool to finish closing. Also, :func:`asyncio.run` has been updated +to utilize the new coroutine. \ No newline at end of file From d2bc6d0083c2a0ff448dc5cab7bd4ebfb84ce62b Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Fri, 13 Sep 2019 15:29:49 -0400 Subject: [PATCH 23/26] Adjust wording in Misc/NEWS entry Co-Authored-By: Yury Selivanov --- Doc/library/asyncio-eventloop.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 0bd6bd5bcf9f53..c8fce4f6ce02e3 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -169,7 +169,7 @@ Running and stopping the loop .. coroutinemethod:: loop.shutdown_default_executor() - Schedule the closure of the default executor, but wait for the + Schedule the closure of the default executor and wait for it to join all threads :class:`ThreadPoolExecutor` to finish joining all of the threads. After calling this method, a :exc:`RuntimeError` will be raised if :meth:`loop.run_in_executor` is called while using the default executor. From 8820584a64ae50c0a84bb61861ce79e85dfe25cc Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Fri, 13 Sep 2019 15:29:49 -0400 Subject: [PATCH 24/26] Adjust wording in doc for loop.shutdown_default_executor() Co-Authored-By: Yury Selivanov --- Doc/library/asyncio-eventloop.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 0bd6bd5bcf9f53..c8fce4f6ce02e3 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -169,7 +169,7 @@ Running and stopping the loop .. coroutinemethod:: loop.shutdown_default_executor() - Schedule the closure of the default executor, but wait for the + Schedule the closure of the default executor and wait for it to join all threads :class:`ThreadPoolExecutor` to finish joining all of the threads. After calling this method, a :exc:`RuntimeError` will be raised if :meth:`loop.run_in_executor` is called while using the default executor. From dbc08ae5bac719634ee3c22fa65e0d5915ca48f1 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Fri, 13 Sep 2019 16:59:49 -0400 Subject: [PATCH 25/26] Fix doc for loop.shutdown_default_executor() After applying the suggestion from @1st1, this adjusts the surrounding wording and flow of the paragraph. --- Doc/library/asyncio-eventloop.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index c8fce4f6ce02e3..2fd4cf30bd450f 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -169,10 +169,10 @@ Running and stopping the loop .. coroutinemethod:: loop.shutdown_default_executor() - Schedule the closure of the default executor and wait for it to join all threads - :class:`ThreadPoolExecutor` to finish joining all of the threads. After - calling this method, a :exc:`RuntimeError` will be raised if - :meth:`loop.run_in_executor` is called while using the default executor. + Schedule the closure of the default executor and wait for it to join all of + the threads in the :class:`ThreadPoolExecutor`. After calling this method, a + :exc:`RuntimeError` will be raised if :meth:`loop.run_in_executor` is called + while using the default executor. Note that there is no need to call this function when :func:`asyncio.run` is used. From fbae3ec0bd6dd967369a2dbaedfcd10931e2df18 Mon Sep 17 00:00:00 2001 From: Kyle Stanley Date: Wed, 18 Sep 2019 18:43:45 -0400 Subject: [PATCH 26/26] Add "Patch by" to news entry --- .../next/Library/2019-09-11-21-38-41.bpo-34037.LIAS_3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2019-09-11-21-38-41.bpo-34037.LIAS_3.rst b/Misc/NEWS.d/next/Library/2019-09-11-21-38-41.bpo-34037.LIAS_3.rst index 2e15cbd12bf734..75345160a2fa31 100644 --- a/Misc/NEWS.d/next/Library/2019-09-11-21-38-41.bpo-34037.LIAS_3.rst +++ b/Misc/NEWS.d/next/Library/2019-09-11-21-38-41.bpo-34037.LIAS_3.rst @@ -1,4 +1,4 @@ For :mod:`asyncio`, add a new coroutine :meth:`loop.shutdown_default_executor`. The new coroutine provides an API to schedule an executor shutdown that waits on the threadpool to finish closing. Also, :func:`asyncio.run` has been updated -to utilize the new coroutine. \ No newline at end of file +to utilize the new coroutine. Patch by Kyle Stanley.