diff options
author | Yury Selivanov <yury@magic.io> | 2018-09-14 20:32:07 (GMT) |
---|---|---|
committer | Carol Willing <carolcode@willingconsulting.com> | 2018-09-14 20:32:07 (GMT) |
commit | 3faaa8857a42a36383bb18425444e597fc876797 (patch) | |
tree | 109c2997624aba5ed64b619938a6ca8a7bf007c1 | |
parent | ad8a0004206ba7aec5a8a60fce413da718080db2 (diff) | |
download | cpython-3faaa8857a42a36383bb18425444e597fc876797.zip cpython-3faaa8857a42a36383bb18425444e597fc876797.tar.gz cpython-3faaa8857a42a36383bb18425444e597fc876797.tar.bz2 |
bpo-33649: Refresh Tasks and Futures pages (#9314)
* bpo-33649: Refresh Tasks and Futures pages
* Fixes
* Fix markup
-rw-r--r-- | Doc/library/asyncio-eventloop.rst | 2 | ||||
-rw-r--r-- | Doc/library/asyncio-future.rst | 240 | ||||
-rw-r--r-- | Doc/library/asyncio-protocol.rst | 18 | ||||
-rw-r--r-- | Doc/library/asyncio-task.rst | 1045 | ||||
-rw-r--r-- | Doc/library/asyncio.rst | 49 |
5 files changed, 759 insertions, 595 deletions
diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index baa5234..e1b47d2 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -1429,7 +1429,7 @@ event loop:: .. seealso:: - A similar :ref:`Hello World <asyncio-hello-world-coroutine>` + A similar :ref:`Hello World <coroutine>` example created with a coroutine and the :func:`run` function. diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst new file mode 100644 index 0000000..2c41c1c --- /dev/null +++ b/Doc/library/asyncio-future.rst @@ -0,0 +1,240 @@ +.. currentmodule:: asyncio + + +======= +Futures +======= + +*Future* objects are used to bridge low-level callback-based code +with high-level async/await code. + + +Future Functions +================ + +.. function:: isfuture(obj) + + Return ``True`` if *obj* is either of: + + * an instance of :class:`asyncio.Future`, + * an instance of :class:`asyncio.Task`, + * a Future-like object with a ``_asyncio_future_blocking`` + attribute. + + .. versionadded:: 3.5 + + +.. function:: ensure_future(obj, \*, loop=None) + + Return: + + * *obj* argument as is, if *obj* is a :class:`Future`, + a :class:`Task`, or a Future-like object (:func:`isfuture` + is used for the test.) + + * a :class:`Task` object wrapping *obj*, if *obj* is a + coroutine (:func:`iscoroutine` is used for the test.) + + * a :class:`Task` object that would await on *obj*, if *obj* is an + awaitable (:func:`inspect.isawaitable` is used for the test.) + + If *obj* is neither of the above a :exc:`TypeError` is raised. + + .. important:: + + See also the :func:`create_task` function which is the + preferred way for creating new Tasks. + + .. versionchanged:: 3.5.1 + The function accepts any :term:`awaitable` object. + + +.. function:: wrap_future(future, \*, loop=None) + + Wrap a :class:`concurrent.futures.Future` object in a + :class:`asyncio.Future` object. + + +Future Object +============= + +.. class:: Future(\*, loop=None) + + A Future represents an eventual result of an asynchronous + operation. Not thread-safe. + + Future is an :term:`awaitable` object. Coroutines can await on + Future objects until they either have a result or an exception + set, or until they are cancelled. + + Typically Futures are used to enable low-level + callback-based code (e.g. in protocols implemented using asyncio + :ref:`transports <asyncio-transports-protocols>`) + to interoperate with high-level async/await code. + + The rule of thumb is to never expose Future objects in user-facing + APIs, and the recommended way to create a Future object is to call + :meth:`loop.create_future`. This way alternative event loop + implementations can inject their own optimized implementations + of a Future object. + + .. versionchanged:: 3.7 + Added support for the :mod:`contextvars` module. + + .. method:: result() + + Return the result of the Future. + + If the Future is *done* and has a result set by the + :meth:`set_result` method, the result value is returned. + + If the Future is *done* and has an exception set by the + :meth:`set_exception` method, this method raises the exception. + + If the Future has been *cancelled*, this method raises + a :exc:`CancelledError` exception. + + If the Future's result isn't yet available, this method raises + a :exc:`InvalidStateError` exception. + + .. method:: set_result(result) + + Mark the Future as *done* and set its result. + + Raises a :exc:`InvalidStateError` error if the Future is + already *done*. + + .. method:: set_exception(exception) + + Mark the Future as *done* and set an exception. + + Raises a :exc:`InvalidStateError` error if the Future is + already *done*. + + .. method:: done() + + Return ``True`` if the Future is *done*. + + A Future is *done* if it was *cancelled* or if it has a result + or an exception set with :meth:`set_result` or + :meth:`set_exception` calls. + + .. method:: add_done_callback(callback, *, context=None) + + Add a callback to be run when the Future is *done*. + + The *callback* is called with the Future object as its only + argument. + + If the Future is already *done* when this method is called, + the callback is scheduled with :meth:`loop.call_soon`. + + 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. + + :func:`functools.partial` can be used to pass parameters + to the callback, e.g.:: + + # Call 'print("Future:", fut)' when "fut" is done. + fut.add_done_callback( + functools.partial(print, "Future:")) + + .. versionchanged:: 3.7 + The *context* keyword-only parameter was added. + See :pep:`567` for more details. + + .. method:: remove_done_callback(callback) + + Remove *callback* from the callbacks list. + + Returns the number of callbacks removed, which is typically 1, + unless a callback was added more than once. + + .. method:: cancel() + + Cancel the Future and schedule callbacks. + + If the Future is already *done* or *cancelled*, return ``False``. + Otherwise, change the Future's state to *cancelled*, + schedule the callbacks, and return ``True``. + + .. method:: exception() + + Return the exception that was set on this Future. + + The exception (or ``None`` if no exception was set) is + returned only if the Future is *done*. + + If the Future has been *cancelled*, this method raises a + :exc:`CancelledError` exception. + + If the Future isn't *done* yet, this method raises an + :exc:`InvalidStateError` exception. + + .. method:: get_loop() + + Return the event loop the Future object is bound to. + + .. versionadded:: 3.7 + + .. method:: cancelled() + + Return ``True`` if the Future was *cancelled*. + + +This example creates a Future object, creates and schedules an +asynchronous Task to set result for the Future, and waits until +the Future has a result:: + + async def set_after(fut, delay, value): + # Sleep for *delay* seconds. + await asyncio.sleep(delay) + + # Set *value* as a result of *fut* Future. + fut.set_result(value) + + async def main(): + # Get the current event loop. + loop = asyncio.get_running_loop() + + # Create a new Future object. + fut = loop.create_future() + + # Run "set_after()" coroutine in a parallel Task. + # We are using the low-level "loop.create_task()" API here because + # we already have a reference to the event loop at hand. + # Otherwise we could have just used "asyncio.create_task()". + loop.create_task( + set_after(fut, 1, '... world')) + + print('hello ...') + + # Wait until *fut* has a result (1 second) and print it. + print(await fut) + + asyncio.run(main()) + + +.. important:: + + The Future object was designed to mimic + :class:`concurrent.futures.Future`. Key differences include: + + - unlike asyncio Futures, :class:`concurrent.futures.Future` + instances cannot be awaited. + + - :meth:`asyncio.Future.result` and :meth:`asyncio.Future.exception` + do not accept the *timeout* argument. + + - :meth:`asyncio.Future.result` and :meth:`asyncio.Future.exception` + raise an :exc:`InvalidStateError` exception when the Future is not + *done*. + + - Callbacks registered with :meth:`asyncio.Future.add_done_callback` + are not called immediately. They are scheduled with + :meth:`loop.call_soon` instead. + + - asyncio Future is not compatible with the + :func:`concurrent.futures.wait` and + :func:`concurrent.futures.as_completed` functions. diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index d7ecb25..e4aed64 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -1,6 +1,9 @@ .. currentmodule:: asyncio +.. _asyncio-transports-protocols: + + ======================== Transports and Protocols ======================== @@ -393,11 +396,13 @@ Subprocess Transports .. method:: SubprocessTransport.kill() - Kill the subprocess, as in :meth:`subprocess.Popen.kill`. + Kill the subprocess. On POSIX systems, the function sends SIGKILL to the subprocess. On Windows, this method is an alias for :meth:`terminate`. + See also :meth:`subprocess.Popen.kill`. + .. method:: SubprocessTransport.send_signal(signal) Send the *signal* number to the subprocess, as in @@ -405,17 +410,20 @@ Subprocess Transports .. method:: SubprocessTransport.terminate() - Ask the subprocess to stop, as in :meth:`subprocess.Popen.terminate`. + Stop the subprocess. On POSIX systems, this method sends SIGTERM to the subprocess. On Windows, the Windows API function TerminateProcess() is called to stop the subprocess. + See also :meth:`subprocess.Popen.terminate`. + .. method:: SubprocessTransport.close() - Kill the subprocess by calling the :meth:`kill` method - if the subprocess hasn't returned yet, and close transports of all - pipes (*stdin*, *stdout* and *stderr*). + Kill the subprocess by calling the :meth:`kill` method. + + If the subprocess hasn't returned yet, and close transports of + *stdin*, *stdout*, and *stderr* pipes. .. _asyncio-protocol: diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 9f4433d..7e09b16 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1,96 +1,118 @@ .. currentmodule:: asyncio -Tasks and coroutines + +==================== +Coroutines and Tasks ==================== -**Source code:** :source:`Lib/asyncio/tasks.py` +This section outlines high-level asyncio APIs to work with coroutines +and Tasks. + +.. contents:: + :depth: 1 + :local: -**Source code:** :source:`Lib/asyncio/coroutines.py` .. _coroutine: Coroutines ----------- +========== -Coroutines used with :mod:`asyncio` may be implemented using the -:keyword:`async def` statement, or by using :term:`generators <generator>`. -The :keyword:`async def` type of coroutine was added in Python 3.5, and -is recommended if there is no need to support older Python versions. +Coroutines declared with async/await syntax is the preferred way of +writing asyncio applications. For example, the following snippet +of code prints "hello", waits 1 second, and prints "world":: -Generator-based coroutines should be decorated with :func:`@asyncio.coroutine -<asyncio.coroutine>`, although this is not strictly enforced. -The decorator enables compatibility with :keyword:`async def` coroutines, -and also serves as documentation. Generator-based -coroutines use the ``yield from`` syntax introduced in :pep:`380`, -instead of the original ``yield`` syntax. + >>> import asyncio -The word "coroutine", like the word "generator", is used for two -different (though related) concepts: + >>> async def main(): + ... print('hello') + ... await asyncio.sleep(1) + ... print('world') -- The function that defines a coroutine - (a function definition using :keyword:`async def` or - decorated with ``@asyncio.coroutine``). If disambiguation is needed - we will call this a *coroutine function* (:func:`iscoroutinefunction` - returns ``True``). + >>> asyncio.run(main()) + hello + world -- The object obtained by calling a coroutine function. This object - represents a computation or an I/O operation (usually a combination) - that will complete eventually. If disambiguation is needed we will - call it a *coroutine object* (:func:`iscoroutine` returns ``True``). +Note that simply calling a coroutine will not schedule it to +be executed:: -Things a coroutine can do: + >>> main() + <coroutine object main at 0x1053bb7c8> -- ``result = await future`` or ``result = yield from future`` -- - suspends the coroutine until the - future is done, then returns the future's result, or raises an - exception, which will be propagated. (If the future is cancelled, - it will raise a ``CancelledError`` exception.) Note that tasks are - futures, and everything said about futures also applies to tasks. +To actually run a coroutine asyncio provides three main mechanisms: -- ``result = await coroutine`` or ``result = yield from coroutine`` -- - wait for another coroutine to - produce a result (or raise an exception, which will be propagated). - The ``coroutine`` expression must be a *call* to another coroutine. +* By using the :func:`asyncio.run` function to run the top-level + entry point "main()" function (see the above example.) -- ``return expression`` -- produce a result to the coroutine that is - waiting for this one using :keyword:`await` or ``yield from``. +* By awaiting on a coroutine. The following snippet of code will + print "hello" after waiting for 1 second, and then print "world" + after waiting for *another* 2 seconds:: -- ``raise exception`` -- raise an exception in the coroutine that is - waiting for this one using :keyword:`await` or ``yield from``. + import asyncio + import time -Calling a coroutine does not start its code running -- -the coroutine object returned by the call doesn't do anything until you -schedule its execution. There are two basic ways to start it running: -call ``await coroutine`` or ``yield from coroutine`` from another coroutine -(assuming the other coroutine is already running!), or schedule its execution -using the :func:`ensure_future` function or the :meth:`loop.create_task` -method. + async def say_after(delay, what): + await asyncio.sleep(delay) + print(what) + async def main(): + print('started at', time.strftime('%X')) -Coroutines (and tasks) can only run when the event loop is running. + await say_after(1, 'hello') + await say_after(2, 'world') -.. decorator:: coroutine + print('finished at', time.strftime('%X')) - Decorator to mark generator-based coroutines. This enables - the generator use :keyword:`!yield from` to call :keyword:`async - def` coroutines, and also enables the generator to be called by - :keyword:`async def` coroutines, for instance using an - :keyword:`await` expression. + asyncio.run(main()) - There is no need to decorate :keyword:`async def` coroutines themselves. + Expected output:: - If the generator is not yielded from before it is destroyed, an error - message is logged. See :ref:`Detect coroutines never scheduled - <asyncio-coroutine-not-scheduled>`. + started at 17:13:52 + hello + world + finished at 17:13:55 -.. note:: +* By using the :func:`asyncio.create_task` function to run coroutines + concurrently as asyncio :class:`Tasks <Task>`. + + Let's modify the above example and run two "set_after" coroutines + *concurrently*:: + + async def main(): + task1 = asyncio.create_task( + say_after(1, 'hello')) + + task2 = asyncio.create_task( + say_after(2, 'world')) + + print('started at', time.strftime('%X')) - In this documentation, some methods are documented as coroutines, - even if they are plain Python functions returning a :class:`Future`. - This is intentional to have a freedom of tweaking the implementation - of these functions in the future. If such a function is needed to be - used in a callback-style code, wrap its result with :func:`ensure_future`. + # Wait until both tasks are completed (should take + # around 2 seconds.) + await task1 + await task2 + print('finished at', time.strftime('%X')) + + Note that expected output now shows that the snippet runs + 1 second faster than before:: + + started at 17:14:32 + hello + world + finished at 17:14:34 + +Note that in this documentation the term "coroutine" can be used for +two closely related concepts: + +* a *coroutine function*: an :keyword:`async def` function; + +* a *coroutine object*: object returned by calling a + *coroutine function*. + + +Running an asyncio Program +========================== .. function:: run(coro, \*, debug=False) @@ -101,7 +123,7 @@ Coroutines (and tasks) can only run when the event loop is running. This function cannot be called when another asyncio event loop is running in the same thread. - If debug is True, the event loop will be run in debug mode. + If *debug* is ``True``, the event loop will be run in debug mode. This function always creates a new event loop and closes it at the end. It should be used as a main entry point for asyncio @@ -112,34 +134,41 @@ Coroutines (and tasks) can only run when the event loop is running. on a :term:`provisional basis <provisional api>`. -.. _asyncio-hello-world-coroutine: +Creating Tasks +============== -Example: Hello World coroutine -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. function:: create_task(coro, \*, name=None) -Example of coroutine displaying ``"Hello World"``:: + Wrap a :ref:`coroutine <coroutine>` *coro* into a task and schedule + its execution. Return the task object. - import asyncio + If *name* is not ``None``, it is set as the name of the task using + :meth:`Task.set_name`. + + The task is executed in :func:`get_running_loop` context, + :exc:`RuntimeError` is raised if there is no running loop in + current thread. + + .. versionadded:: 3.7 - async def hello_world(): - print("Hello World!") + .. versionchanged:: 3.8 + Added the ``name`` parameter. - asyncio.run(hello_world()) -.. seealso:: +Sleeping +======== - The :ref:`Hello World with call_soon() <asyncio-hello-world-callback>` - example uses the :meth:`loop.call_soon` method to schedule a - callback. +.. coroutinefunction:: sleep(delay, result=None, \*, loop=None) + Block for *delay* seconds. -.. _asyncio-date-coroutine: + If *result* is provided, it is returned to the caller + when the coroutine completes. -Example: Coroutine displaying the current date -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. _asyncio-date-coroutine: -Example of coroutine displaying the current date every second during 5 seconds -using the :meth:`sleep` function:: + Example of coroutine displaying the current date every second + during 5 seconds:: import asyncio import datetime @@ -155,418 +184,279 @@ using the :meth:`sleep` function:: asyncio.run(display_date()) -.. seealso:: - - The :ref:`display the current date with call_later() - <asyncio-date-callback>` example uses a callback with the - :meth:`loop.call_later` method. - - -Example: Chain coroutines -^^^^^^^^^^^^^^^^^^^^^^^^^ - -Example chaining coroutines:: - - import asyncio - - async def compute(x, y): - print("Compute %s + %s ..." % (x, y)) - await asyncio.sleep(1.0) - return x + y - - async def print_sum(x, y): - result = await compute(x, y) - print("%s + %s = %s" % (x, y, result)) - - loop = asyncio.get_event_loop() - loop.run_until_complete(print_sum(1, 2)) - loop.close() - -``compute()`` is chained to ``print_sum()``: ``print_sum()`` coroutine waits -until ``compute()`` is completed before returning its result. - -Sequence diagram of the example: - -.. image:: tulip_coro.png - :align: center - -The "Task" is created by the :meth:`loop.run_until_complete` method -when it gets a coroutine object instead of a task. - -The diagram shows the control flow, it does not describe exactly how things -work internally. For example, the sleep coroutine creates an internal future -which uses :meth:`loop.call_later` to wake up the task in 1 second. - - -Future ------- - -.. class:: Future(\*, loop=None) - - This class is *almost* compatible with :class:`concurrent.futures.Future`. - - Differences: - - - :meth:`result` and :meth:`exception` do not take a timeout argument and - raise an exception when the future isn't done yet. - - - Callbacks registered with :meth:`add_done_callback` are always called - via the event loop's :meth:`loop.call_soon`. - - - This class is not compatible with the :func:`~concurrent.futures.wait` and - :func:`~concurrent.futures.as_completed` functions in the - :mod:`concurrent.futures` package. - - This class is :ref:`not thread safe <asyncio-multithreading>`. - - .. method:: cancel() - - Cancel the future and schedule callbacks. - - If the future is already done or cancelled, return ``False``. Otherwise, - change the future's state to cancelled, schedule the callbacks and return - ``True``. - - .. method:: cancelled() - - Return ``True`` if the future was cancelled. - - .. method:: done() - - Return ``True`` if the future is done. - - Done means either that a result / exception are available, or that the - future was cancelled. - .. method:: result() +Running Tasks Concurrently +========================== - Return the result this future represents. +.. coroutinefunction:: gather(\*fs, loop=None, return_exceptions=False) - If the future has been cancelled, raises :exc:`CancelledError`. If the - future's result isn't yet available, raises :exc:`InvalidStateError`. If - the future is done and has an exception set, this exception is raised. + Return a Future aggregating results from the given coroutine objects, + Tasks, or Futures. - .. method:: exception() + If all Tasks/Futures are completed successfully, the result is an + aggregate list of returned values. The result values are in the + order of the original *fs* sequence. - Return the exception that was set on this future. + All coroutines in the *fs* list are automatically + wrapped in :class:`Tasks <Task>`. - The exception (or ``None`` if no exception was set) is returned only if - the future is done. If the future has been cancelled, raises - :exc:`CancelledError`. If the future isn't done yet, raises - :exc:`InvalidStateError`. + If *return_exceptions* is ``True``, exceptions in the Tasks/Futures + are treated the same as successful results, and gathered in the + result list. Otherwise, the first raised exception is immediately + propagated to the returned Future. - .. method:: add_done_callback(callback, *, context=None) + If the outer Future is *cancelled*, all submitted Tasks/Futures + (that have not completed yet) are also *cancelled*. - Add a callback to be run when the future becomes done. + If any child is *cancelled*, it is treated as if it raised + :exc:`CancelledError` -- the outer Future is **not** cancelled in + this case. This is to prevent the cancellation of one submitted + Task/Future to cause other Tasks/Futures to be cancelled. - The *callback* is called with a single argument - the future object. If the - future is already done when this is called, the callback is scheduled - with :meth:`loop.call_soon`. + All futures must share the same event loop. - 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. - - :ref:`Use functools.partial to pass parameters to the callback - <asyncio-pass-keywords>`. For example, - ``fut.add_done_callback(functools.partial(print, "Future:", - flush=True))`` will call ``print("Future:", fut, flush=True)``. - - .. versionchanged:: 3.7 - The *context* keyword-only parameter was added. See :pep:`567` - for more details. - - .. method:: remove_done_callback(fn) - - Remove all instances of a callback from the "call when done" list. - - Returns the number of callbacks removed. - - .. method:: set_result(result) - - Mark the future done and set its result. - - If the future is already done when this method is called, raises - :exc:`InvalidStateError`. - - .. method:: set_exception(exception) - - Mark the future done and set an exception. - - If the future is already done when this method is called, raises - :exc:`InvalidStateError`. - - .. method:: get_loop() - - Return the event loop the future object is bound to. + .. versionchanged:: 3.7 + If the *gather* itself is cancelled, the cancellation is + propagated regardless of *return_exceptions*. - .. versionadded:: 3.7 + Example:: + import asyncio -Example: Future with run_until_complete() -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + async def factorial(name, number): + f = 1 + for i in range(2, number + 1): + print(f"Task {name}: Compute factorial({i})...") + await asyncio.sleep(1) + f *= i + print(f"Task {name}: factorial({number}) = {f}") -Example combining a :class:`Future` and a :ref:`coroutine function -<coroutine>`:: + async def main(): + await asyncio.gather( + factorial("A", 2), + factorial("B", 3), + factorial("C", 4), + )) - import asyncio + asyncio.run(main()) - async def slow_operation(future): - await asyncio.sleep(1) - future.set_result('Future is done!') + # Expected output: + # + # Task A: Compute factorial(2)... + # Task B: Compute factorial(2)... + # Task C: Compute factorial(2)... + # Task A: factorial(2) = 2 + # Task B: Compute factorial(3)... + # Task C: Compute factorial(3)... + # Task B: factorial(3) = 6 + # Task C: Compute factorial(4)... + # Task C: factorial(4) = 24 - loop = asyncio.get_event_loop() - future = asyncio.Future() - asyncio.ensure_future(slow_operation(future)) - loop.run_until_complete(future) - print(future.result()) - loop.close() -The coroutine function is responsible for the computation (which takes 1 second) -and it stores the result into the future. The -:meth:`loop.run_until_complete` method waits for the completion of -the future. +Shielding Tasks From Cancellation +================================= -.. note:: - The :meth:`loop.run_until_complete` method uses internally the - :meth:`~Future.add_done_callback` method to be notified when the future is - done. +.. coroutinefunction:: shield(fut, \*, loop=None) + Wait for a Future/Task while protecting it from being cancelled. -Example: Future with run_forever() -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + *fut* can be a coroutine, a Task, or a Future-like object. If + *fut* is a coroutine it is automatically wrapped in a + :class:`Task`. -The previous example can be written differently using the -:meth:`Future.add_done_callback` method to describe explicitly the control -flow:: + The statement:: - import asyncio + res = await shield(something()) - async def slow_operation(future): - await asyncio.sleep(1) - future.set_result('Future is done!') + is equivalent to the statement:: - def got_result(future): - print(future.result()) - loop.stop() + res = await something() - loop = asyncio.get_event_loop() - future = asyncio.Future() - asyncio.ensure_future(slow_operation(future)) - future.add_done_callback(got_result) - try: - loop.run_forever() - finally: - loop.close() + *except* that if the coroutine containing it is cancelled, the + Task running in ``something()`` is not cancelled. From the point + of view of ``something()``, the cancellation did not happen. + Although its caller is still cancelled, so the "await" expression + still raises :exc:`CancelledError`. -In this example, the future is used to link ``slow_operation()`` to -``got_result()``: when ``slow_operation()`` is done, ``got_result()`` is called -with the result. + If ``something()`` is cancelled by other means (i.e. from within + itself) that would also cancel ``shield()``. + If it is desired to completely ignore cancellation (not recommended) + the ``shield()`` function should be combined with a try/except + clause, as follows:: -Task ----- + try: + res = await shield(something()) + except CancelledError: + res = None -.. function:: create_task(coro, \*, name=None) - Wrap a :ref:`coroutine <coroutine>` *coro* into a task and schedule - its execution. Return the task object. +Timeouts +======== - If *name* is not ``None``, it is set as the name of the task using - :meth:`Task.set_name`. +.. coroutinefunction:: wait_for(fut, timeout, \*, loop=None) - The task is executed in :func:`get_running_loop` context, - :exc:`RuntimeError` is raised if there is no running loop in - current thread. + Wait for the coroutine, Task, or Future to complete with timeout. - .. versionadded:: 3.7 + *fut* can be a coroutine, a Task, or a Future-like object. If + *fut* is a coroutine it is automatically wrapped in a + :class:`Task`. - .. versionchanged:: 3.8 - Added the ``name`` parameter. + *timeout* can either be ``None`` or a float or int number of seconds + to wait for. If *timeout* is ``None``, block until the future + completes. -.. class:: Task(coro, \*, loop=None, name=None) + If a timeout occurs, it cancels the task and raises + :exc:`asyncio.TimeoutError`. - A unit for concurrent running of :ref:`coroutines <coroutine>`, - subclass of :class:`Future`. + To avoid the task cancellation, wrap it in :func:`shield`. - A task is responsible for executing a coroutine object in an event loop. If - the wrapped coroutine yields from a future, the task suspends the execution - of the wrapped coroutine and waits for the completion of the future. When - the future is done, the execution of the wrapped coroutine restarts with the - result or the exception of the future. + The function will wait until the future is actually cancelled, + so the total wait time may exceed the *timeout*. - Event loops use cooperative scheduling: an event loop only runs one task at - a time. Other tasks may run in parallel if other event loops are - running in different threads. While a task waits for the completion of a - future, the event loop executes a new task. + If the wait is cancelled, the future *fut* is also cancelled. - The cancellation of a task is different from the cancellation of a - future. Calling :meth:`cancel` will throw a - :exc:`~concurrent.futures.CancelledError` to the wrapped - coroutine. :meth:`~Future.cancelled` only returns ``True`` if the - wrapped coroutine did not catch the - :exc:`~concurrent.futures.CancelledError` exception, or raised a - :exc:`~concurrent.futures.CancelledError` exception. + Example:: - If a pending task is destroyed, the execution of its wrapped :ref:`coroutine - <coroutine>` did not complete. It is probably a bug and a warning is - logged: see :ref:`Pending task destroyed <asyncio-pending-task-destroyed>`. + async def eternity(): + # Sleep for one hour + await asyncio.sleep(3600) + print('yay!') - Don't directly create :class:`Task` instances: use the :func:`create_task` - function or the :meth:`loop.create_task` method. + async def main(): + # Wait for at most 1 second + try: + await asyncio.wait_for(eternity(), timeout=1.0) + except asyncio.TimeoutError: + print('timeout!') - Tasks support the :mod:`contextvars` module. When a Task - is created it copies the current context and later runs its coroutine - in the copied context. See :pep:`567` for more details. + asyncio.run(main()) - This class is :ref:`not thread safe <asyncio-multithreading>`. + # Expected output: + # + # timeout! .. versionchanged:: 3.7 - Added support for the :mod:`contextvars` module. - - .. versionchanged:: 3.8 - Added the ``name`` parameter. + When *fut* is cancelled due to a timeout, ``wait_for`` waits + for *fut* to be cancelled. Previously, it raised + :exc:`asyncio.TimeoutError` immediately. - .. classmethod:: all_tasks(loop=None) - Return a set of all tasks for an event loop. +Waiting Primitives +================== - By default all tasks for the current event loop are returned. - If *loop* is ``None``, :func:`get_event_loop` function - is used to get the current loop. - - .. classmethod:: current_task(loop=None) - - Return the currently running task in an event loop or ``None``. - - By default the current task for the current event loop is returned. - - ``None`` is returned when called not in the context of a :class:`Task`. - - .. method:: cancel() - - Request that this task cancel itself. - - This arranges for a :exc:`~concurrent.futures.CancelledError` to be - thrown into the wrapped coroutine on the next cycle through the event - loop. The coroutine then has a chance to clean up or even deny the - request using try/except/finally. +.. coroutinefunction:: wait(fs, \*, loop=None, timeout=None,\ + return_when=ALL_COMPLETED) - Unlike :meth:`Future.cancel`, this does not guarantee that the task - will be cancelled: the exception might be caught and acted upon, delaying - cancellation of the task or preventing cancellation completely. The task - may also return a value or raise a different exception. + Wait for a set of Futures to complete. - Immediately after this method is called, :meth:`~Future.cancelled` will - not return ``True`` (unless the task was already cancelled). A task will - be marked as cancelled when the wrapped coroutine terminates with a - :exc:`~concurrent.futures.CancelledError` exception (even if - :meth:`cancel` was not called). + *fs* is a list of coroutines, Futures, and/or Tasks. Coroutines + are automatically wrapped in :class:`Tasks <Task>`. - .. method:: get_stack(\*, limit=None) + Returns two sets of Tasks/Futures: ``(done, pending)``. - Return the list of stack frames for this task's coroutine. + *timeout* (a float or int), if specified, can be used to control + the maximum number of seconds to wait before returning. - If the coroutine is not done, this returns the stack where it is - suspended. If the coroutine has completed successfully or was - cancelled, this returns an empty list. If the coroutine was - terminated by an exception, this returns the list of traceback - frames. + Note that this function does not raise :exc:`asyncio.TimeoutError`. + Futures or Tasks that aren't done when the timeout occurs are just + returned in the second set. - The frames are always ordered from oldest to newest. + *return_when* indicates when this function should return. It must + be one of the following constants: - The optional limit gives the maximum number of frames to return; by - default all available frames are returned. Its meaning differs depending - on whether a stack or a traceback is returned: the newest frames of a - stack are returned, but the oldest frames of a traceback are returned. - (This matches the behavior of the traceback module.) + .. tabularcolumns:: |l|L| - For reasons beyond our control, only one stack frame is returned for a - suspended coroutine. + +-----------------------------+----------------------------------------+ + | Constant | Description | + +=============================+========================================+ + | :const:`FIRST_COMPLETED` | The function will return when any | + | | future finishes or is cancelled. | + +-----------------------------+----------------------------------------+ + | :const:`FIRST_EXCEPTION` | The function will return when any | + | | future finishes by raising an | + | | exception. If no future raises an | + | | exception then it is equivalent to | + | | :const:`ALL_COMPLETED`. | + +-----------------------------+----------------------------------------+ + | :const:`ALL_COMPLETED` | The function will return when all | + | | futures finish or are cancelled. | + +-----------------------------+----------------------------------------+ - .. method:: print_stack(\*, limit=None, file=None) + Unlike :func:`~asyncio.wait_for`, ``wait()`` does not cancel the + futures when a timeout occurs. - Print the stack or traceback for this task's coroutine. + Usage:: - This produces output similar to that of the traceback module, for the - frames retrieved by get_stack(). The limit argument is passed to - get_stack(). The file argument is an I/O stream to which the output - is written; by default output is written to sys.stderr. + done, pending = await asyncio.wait(fs) - .. method:: get_name() - Return the name of the task. +.. function:: as_completed(fs, \*, loop=None, timeout=None) - If no name has been explicitly assigned to the task, the default - ``Task`` implementation generates a default name during instantiation. + Return an iterator which values, when waited for, are + :class:`Future` instances. - .. versionadded:: 3.8 + Raises :exc:`asyncio.TimeoutError` if the timeout occurs before + all Futures are done. - .. method:: set_name(value) + Example:: - Set the name of the task. + for f in as_completed(fs): + result = await f + # ... - The *value* argument can be any object, which is then converted to a - string. - In the default ``Task`` implementation, the name will be visible in the - :func:`repr` output of a task object. +Scheduling From Other Threads +============================= - .. versionadded:: 3.8 +.. function:: run_coroutine_threadsafe(coro, loop) + Submit a coroutine to the given event loop. Thread-safe. -Example: Parallel execution of tasks -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Return a :class:`concurrent.futures.Future` to access the result. -Example executing 3 tasks (A, B, C) in parallel:: + This function is meant to be called from a different OS thread + than the one where the event loop is running. Example:: - import asyncio + # Create a coroutine + coro = asyncio.sleep(1, result=3) - async def factorial(name, number): - f = 1 - for i in range(2, number+1): - print("Task %s: Compute factorial(%s)..." % (name, i)) - await asyncio.sleep(1) - f *= i - print("Task %s: factorial(%s) = %s" % (name, number, f)) + # Submit the coroutine to a given loop + future = asyncio.run_coroutine_threadsafe(coro, loop) - loop = asyncio.get_event_loop() - loop.run_until_complete(asyncio.gather( - factorial("A", 2), - factorial("B", 3), - factorial("C", 4), - )) - loop.close() + # Wait for the result with an optional timeout argument + assert future.result(timeout) == 3 -Output:: + If an exception is raised in the coroutine, the returned Future + will be notified. It can also be used to cancel the task in + the event loop:: - Task A: Compute factorial(2)... - Task B: Compute factorial(2)... - Task C: Compute factorial(2)... - Task A: factorial(2) = 2 - Task B: Compute factorial(3)... - Task C: Compute factorial(3)... - Task B: factorial(3) = 6 - Task C: Compute factorial(4)... - Task C: factorial(4) = 24 + try: + result = future.result(timeout) + except asyncio.TimeoutError: + print('The coroutine took too long, cancelling the task...') + future.cancel() + except Exception as exc: + print('The coroutine raised an exception: {!r}'.format(exc)) + else: + print('The coroutine returned: {!r}'.format(result)) -A task is automatically scheduled for execution when it is created. The event -loop stops when all tasks are done. + See the :ref:`concurrency and multithreading <asyncio-multithreading>` + section of the documentation. + Unlike other asyncio functions this functions requires the *loop* + argument to be passed explicitly. -Task functions --------------- + .. versionadded:: 3.5.1 -.. note:: - In the functions below, the optional *loop* argument allows explicitly setting - the event loop object used by the underlying task or coroutine. If it's - not provided, the default event loop is used. +Introspection +============= .. function:: current_task(loop=None) - Return the current running :class:`Task` instance or ``None``, if + Return the currently running :class:`Task` instance, or ``None`` if no task is running. If *loop* is ``None`` :func:`get_running_loop` is used to get @@ -577,246 +467,259 @@ Task functions .. function:: all_tasks(loop=None) - Return a set of :class:`Task` objects created for the loop. + Return a set of not yet finished :class:`Task` objects run by + the loop. If *loop* is ``None``, :func:`get_running_loop` is used for getting - current loop (contrary to the deprecated :meth:`Task.all_tasks` method - that uses :func:`get_event_loop`.) + current loop. .. versionadded:: 3.7 -.. function:: as_completed(fs, \*, loop=None, timeout=None) +Task Object +=========== - Return an iterator whose values, when waited for, are :class:`Future` - instances. +.. class:: Task(coro, \*, loop=None, name=None) - Raises :exc:`asyncio.TimeoutError` if the timeout occurs before all Futures - are done. + A :class:`Future`-like object that wraps a Python + :ref:`coroutine <coroutine>`. Not thread-safe. - Example:: + Tasks are used to run coroutines in event loops. + If a coroutine awaits on a Future, the Task suspends + the execution of the coroutine and waits for the completion + of the Future. When the Future is *done*, the execution of + the wrapped coroutine resumes. - for f in as_completed(fs): - result = await f # The 'await' may raise - # Use result + Event loops use cooperative scheduling: an event loop runs + one Task at a time. While a Task awaits for the completion of a + Future, the event loop runs other Tasks, callbacks, or performs + IO operations. - .. note:: + Use the high-level :func:`asyncio.create_task` function to create + Tasks, or low-level :meth:`loop.create_task` or + :func:`ensure_future` functions. Manually instantiating Task + objects is discouraged. - The futures ``f`` are not necessarily members of fs. + To cancel a running Task use the :meth:`cancel` method. Calling it + will cause the Task to throw a :exc:`CancelledError` exception into + the wrapped coroutine. If a coroutine is awaiting on a Future + object during cancellation, the Future object will be cancelled. -.. function:: ensure_future(coro_or_future, \*, loop=None) + :meth:`cancelled` can be used to check if the Task was cancelled. + The method returns ``True`` if the wrapped coroutine did not + suppress the :exc:`CancelledError` exception and was actually + cancelled. - Schedule the execution of a :ref:`coroutine object <coroutine>`: wrap it in - a future. Return a :class:`Task` object. + :class:`asyncio.Task` inherits from :class:`Future` all of its + APIs except :meth:`Future.set_result` and + :meth:`Future.set_exception`. - If the argument is a :class:`Future`, it is returned directly. + Tasks support the :mod:`contextvars` module. When a Task + is created it copies the current context and later runs its + coroutine in the copied context. - .. versionadded:: 3.4.4 + .. versionchanged:: 3.7 + Added support for the :mod:`contextvars` module. - .. versionchanged:: 3.5.1 - The function accepts any :term:`awaitable` object. + .. versionchanged:: 3.8 + Added the ``name`` parameter. - .. note:: + .. method:: cancel() - :func:`create_task` (added in Python 3.7) is the preferable way - for spawning new tasks. + Request the Task to be cancelled. - .. seealso:: + This arranges for a :exc:`CancelledError` exception to be thrown + into the wrapped coroutine on the next cycle of the event loop. - The :func:`create_task` function and - :meth:`loop.create_task` method. + The coroutine then has a chance to clean up or even deny the + request by suppressing the exception with a :keyword:`try` ... + ... ``except CancelledError`` ... :keyword:`finally` block. + Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does + not guarantee that the Task will be cancelled, although + suppressing cancellation completely is not common and is actively + discouraged. -.. function:: wrap_future(future, \*, loop=None) + The following example illustrates how coroutines can intercept + the cancellation request:: - Wrap a :class:`concurrent.futures.Future` object in a :class:`Future` - object. + async def cancel_me(): + print('cancel_me(): before sleep') -.. function:: gather(\*coros_or_futures, loop=None, return_exceptions=False) + try: + # Wait for 1 hour + await asyncio.sleep(3600) + except asyncio.CancelledError: + print('cancel_me(): cancel sleep') + raise + finally: + print('cancel_me(): after sleep') - Return a future aggregating results from the given coroutine objects or - futures. + async def main(): + # Create a "cancel_me" Task + task = asyncio.create_task(cancel_me()) - All futures must share the same event loop. If all the tasks are done - successfully, the returned future's result is the list of results (in the - order of the original sequence, not necessarily the order of results - arrival). If *return_exceptions* is true, exceptions in the tasks are - treated the same as successful results, and gathered in the result list; - otherwise, the first raised exception will be immediately propagated to the - returned future. + # Wait for 1 second + await asyncio.sleep(1) - Cancellation: if the outer Future is cancelled, all children (that have not - completed yet) are also cancelled. If any child is cancelled, this is - treated as if it raised :exc:`~concurrent.futures.CancelledError` -- the - outer Future is *not* cancelled in this case. (This is to prevent the - cancellation of one child to cause other children to be cancelled.) + task.cancel() + try: + await task + except asyncio.CancelledError: + print("main(): cancel_me is cancelled now") - .. versionchanged:: 3.7.0 - If the *gather* itself is cancelled, the cancellation is propagated - regardless of *return_exceptions*. + asyncio.run(main()) -.. function:: iscoroutine(obj) + # Expected output: + # + # cancel_me(): before sleep + # cancel_me(): cancel sleep + # cancel_me(): after sleep + # main(): cancel_me is cancelled now - Return ``True`` if *obj* is a :ref:`coroutine object <coroutine>`, - which may be based on a generator or an :keyword:`async def` coroutine. + .. method:: cancelled() -.. function:: iscoroutinefunction(func) + Return ``True`` if the Task is *cancelled*. - Return ``True`` if *func* is determined to be a :ref:`coroutine function - <coroutine>`, which may be a decorated generator function or an - :keyword:`async def` function. + The Task is *cancelled* when the cancellation was requested with + :meth:`cancel` and the wrapped coroutine propagated the + :exc:`CancelledError` exception thrown into it. -.. function:: run_coroutine_threadsafe(coro, loop) + .. method:: done() - Submit a :ref:`coroutine object <coroutine>` to a given event loop. + Return ``True`` if the Task is *done*. - Return a :class:`concurrent.futures.Future` to access the result. + A Task is *done* when the wrapped coroutine either returned + a value, raised an exception, or the Task was cancelled. - This function is meant to be called from a different thread than the one - where the event loop is running. Usage:: + .. method:: get_stack(\*, limit=None) - # Create a coroutine - coro = asyncio.sleep(1, result=3) - # Submit the coroutine to a given loop - future = asyncio.run_coroutine_threadsafe(coro, loop) - # Wait for the result with an optional timeout argument - assert future.result(timeout) == 3 + Return the list of stack frames for this Task. - If an exception is raised in the coroutine, the returned future will be - notified. It can also be used to cancel the task in the event loop:: + If the wrapped coroutine is not done, this returns the stack + where it is suspended. If the coroutine has completed + successfully or was cancelled, this returns an empty list. + If the coroutine was terminated by an exception, this returns + the list of traceback frames. - try: - result = future.result(timeout) - except asyncio.TimeoutError: - print('The coroutine took too long, cancelling the task...') - future.cancel() - except Exception as exc: - print('The coroutine raised an exception: {!r}'.format(exc)) - else: - print('The coroutine returned: {!r}'.format(result)) + The frames are always ordered from oldest to newest. - See the :ref:`concurrency and multithreading <asyncio-multithreading>` - section of the documentation. + Only one stack frame is returned for a suspended coroutine. - .. note:: + The optional *limit* argument sets the maximum number of frames + to return; by default all available frames are returned. + The ordering of the returned list differs depending on whether + a stack or a traceback is returned: the newest frames of a + stack are returned, but the oldest frames of a traceback are + returned. (This matches the behavior of the traceback module.) - Unlike other functions from the module, - :func:`run_coroutine_threadsafe` requires the *loop* argument to - be passed explicitly. + .. method:: print_stack(\*, limit=None, file=None) - .. versionadded:: 3.5.1 + Print the stack or traceback for this Task. -.. coroutinefunction:: sleep(delay, result=None, \*, loop=None) + This produces output similar to that of the traceback module + for the frames retrieved by :meth:`get_stack`. - Create a :ref:`coroutine <coroutine>` that completes after a given - time (in seconds). If *result* is provided, it is produced to the caller - when the coroutine completes. + The *limit* argument is passed to :meth:`get_stack` directly. - The resolution of the sleep depends on the :ref:`granularity of the event - loop <asyncio-delayed-calls>`. + The *file* argument is an I/O stream to which the output + is written; by default output is written to :data:`sys.stderr`. - This function is a :ref:`coroutine <coroutine>`. + .. method:: get_name() -.. coroutinefunction:: shield(arg, \*, loop=None) + Return the name of the Task. - Wait for a future, shielding it from cancellation. + If no name has been explicitly assigned to the Task, the default + asyncio Task implementation generates a default name during + instantiation. - The statement:: + .. versionadded:: 3.8 - res = await shield(something()) + .. method:: set_name(value) - is exactly equivalent to the statement:: + Set the name of the Task. - res = await something() + The *value* argument can be any object, which is then + converted to a string. - *except* that if the coroutine containing it is cancelled, the task running - in ``something()`` is not cancelled. From the point of view of - ``something()``, the cancellation did not happen. But its caller is still - cancelled, so the yield-from expression still raises - :exc:`~concurrent.futures.CancelledError`. Note: If ``something()`` is - cancelled by other means this will still cancel ``shield()``. + In the default Task implementation, the name will be visible + in the :func:`repr` output of a task object. - If you want to completely ignore cancellation (not recommended) you can - combine ``shield()`` with a try/except clause, as follows:: + .. versionadded:: 3.8 - try: - res = await shield(something()) - except CancelledError: - res = None + .. classmethod:: all_tasks(loop=None) + Return a set of all tasks for an event loop. -.. coroutinefunction:: wait(futures, \*, loop=None, timeout=None,\ - return_when=ALL_COMPLETED) + By default all tasks for the current event loop are returned. + If *loop* is ``None``, the :func:`get_event_loop` function + is used to get the current loop. - Wait for the Futures and coroutine objects given by the sequence *futures* - to complete. Coroutines will be wrapped in Tasks. Returns two sets of - :class:`Future`: (done, pending). + This function is **deprecated** and scheduled for removal in + Python 3.9. Use the :func:`all_tasks` function instead. - The sequence *futures* must not be empty. + .. classmethod:: current_task(loop=None) - *timeout* can be used to control the maximum number of seconds to wait before - returning. *timeout* can be an int or float. If *timeout* is not specified - or ``None``, there is no limit to the wait time. + Return the currently running task or ``None``. - *return_when* indicates when this function should return. It must be one of - the following constants of the :mod:`concurrent.futures` module: + If *loop* is ``None``, the :func:`get_event_loop` function + is used to get the current loop. - .. tabularcolumns:: |l|L| + This function is **deprecated** and scheduled for removal in + Python 3.9. Use the :func:`current_task` function instead. - +-----------------------------+----------------------------------------+ - | Constant | Description | - +=============================+========================================+ - | :const:`FIRST_COMPLETED` | The function will return when any | - | | future finishes or is cancelled. | - +-----------------------------+----------------------------------------+ - | :const:`FIRST_EXCEPTION` | The function will return when any | - | | future finishes by raising an | - | | exception. If no future raises an | - | | exception then it is equivalent to | - | | :const:`ALL_COMPLETED`. | - +-----------------------------+----------------------------------------+ - | :const:`ALL_COMPLETED` | The function will return when all | - | | futures finish or are cancelled. | - +-----------------------------+----------------------------------------+ - Unlike :func:`~asyncio.wait_for`, ``wait()`` will not cancel the futures - when a timeout occurs. +.. _asyncio_generator_based_coro: - This function is a :ref:`coroutine <coroutine>`. +Generator-based Coroutines +========================== - Usage:: +.. note:: - done, pending = await asyncio.wait(fs) + Support for generator-based coroutines is **deprecated** and + scheduled for removal in Python 4.0. - .. note:: +Generator-based coroutines predate async/await syntax. They are +Python generators that use ``yield from`` expression is to await +on Futures and other coroutines. - This does not raise :exc:`asyncio.TimeoutError`! Futures that aren't done - when the timeout occurs are returned in the second set. +Generator-based coroutines should be decorated with +:func:`@asyncio.coroutine <asyncio.coroutine>`, although this is not +enforced. -.. coroutinefunction:: wait_for(fut, timeout, \*, loop=None) +.. decorator:: coroutine - Wait for the single :class:`Future` or :ref:`coroutine object <coroutine>` - to complete with timeout. If *timeout* is ``None``, block until the future - completes. + Decorator to mark generator-based coroutines. - Coroutine will be wrapped in :class:`Task`. + This decorator enables legacy generator-based coroutines to be + compatible with async/await code:: - Returns result of the Future or coroutine. When a timeout occurs, it - cancels the task and raises :exc:`asyncio.TimeoutError`. To avoid the task - cancellation, wrap it in :func:`shield`. The function will wait until - the future is actually cancelled, so the total wait time may exceed - the *timeout*. + @asyncio.coroutine + def old_style_coroutine(): + yield from asyncio.sleep(1) - If the wait is cancelled, the future *fut* is also cancelled. + async def main(): + await old_style_coroutine() + + This decorator is **deprecated** and is scheduled for removal in + Python 4.0. - This function is a :ref:`coroutine <coroutine>`, usage:: + This decorator should not be used for :keyword:`async def` + coroutines. - result = await asyncio.wait_for(fut, 60.0) +.. function:: iscoroutine(obj) - .. versionchanged:: 3.4.3 - If the wait is cancelled, the future *fut* is now also cancelled. + Return ``True`` if *obj* is a :ref:`coroutine object <coroutine>`. - .. versionchanged:: 3.7 - When *fut* is cancelled due to a timeout, ``wait_for`` now waits - for *fut* to be cancelled. Previously, - it raised :exc:`~asyncio.TimeoutError` immediately. + This method is different from :func:`inspect.iscoroutine` because + it returns ``True`` for generator-based coroutines decorated with + :func:`@coroutine <coroutine>`. + +.. function:: iscoroutinefunction(func) + + Return ``True`` if *func* is a :ref:`coroutine function + <coroutine>`. + + This method is different from :func:`inspect.iscoroutinefunction` + because it returns ``True`` for generator-based coroutine functions + decorated with :func:`@coroutine <coroutine>`. diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst index 0d58a94..2c8ccbb 100644 --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -1,15 +1,13 @@ -:mod:`asyncio` --- Asynchronous I/O, event loop, coroutines and tasks -===================================================================== +:mod:`asyncio` --- Asynchronous I/O +=================================== .. module:: asyncio - :synopsis: Asynchronous I/O, event loop, coroutines and tasks. - -.. versionadded:: 3.4 - -**Source code:** :source:`Lib/asyncio/` + :synopsis: Asynchronous I/O. -------------- +.. TODO: rewrite the introduction section + This module provides infrastructure for writing single-threaded concurrent code using coroutines, multiplexing I/O access over sockets and other resources, running network clients and servers, and other related primitives. @@ -44,25 +42,40 @@ programming: see the :ref:`Develop with asyncio <asyncio-dev>` page which lists common traps and explains how to avoid them. :ref:`Enable the debug mode <asyncio-debug-mode>` during development to detect common issues. -Table of contents: +High-level APIs: .. toctree:: - :maxdepth: 3 + :maxdepth: 1 - asyncio-eventloop.rst - asyncio-policy.rst - asyncio-platforms.rst asyncio-task.rst - asyncio-protocol.rst asyncio-stream.rst - asyncio-subprocess.rst asyncio-sync.rst + asyncio-subprocess.rst asyncio-queue.rst - asyncio-dev.rst asyncio-exceptions.rst -.. seealso:: +Low-level APIs: + +.. toctree:: + :maxdepth: 1 - The :mod:`asyncio` module was designed in :PEP:`3156`. For a - motivational primer on transports and protocols, see :PEP:`3153`. + asyncio-eventloop.rst + asyncio-future.rst + asyncio-protocol.rst + asyncio-policy.rst + asyncio-platforms.rst + +Guides and Tutorials: + +.. toctree:: + :maxdepth: 1 + + asyncio-dev.rst + + +.. seealso:: + The :mod:`asyncio` module was proposed in :PEP:`3156`. + Since the acceptance of the PEP many new APIs were added and many + original APIs were altered. The PEP should be treated as a + historical document. |