mirror of https://github.com/python/cpython
bpo-33649: More improvements (GH-9439)
This commit is contained in:
parent
8213eaddf3
commit
e247b46cba
|
@ -755,7 +755,7 @@ Watching file descriptors
|
||||||
invoke *callback* with the specified arguments once *fd* is available for
|
invoke *callback* with the specified arguments once *fd* is available for
|
||||||
writing.
|
writing.
|
||||||
|
|
||||||
Use :func:`functools.partial` :ref:`to pass keywords
|
Use :func:`functools.partial` :ref:`to pass keyword arguments
|
||||||
<asyncio-pass-keywords>` to *func*.
|
<asyncio-pass-keywords>` to *func*.
|
||||||
|
|
||||||
.. method:: loop.remove_writer(fd)
|
.. method:: loop.remove_writer(fd)
|
||||||
|
@ -969,7 +969,7 @@ Unix signals
|
||||||
Raise :exc:`ValueError` if the signal number is invalid or uncatchable.
|
Raise :exc:`ValueError` if the signal number is invalid or uncatchable.
|
||||||
Raise :exc:`RuntimeError` if there is a problem setting up the handler.
|
Raise :exc:`RuntimeError` if there is a problem setting up the handler.
|
||||||
|
|
||||||
Use :func:`functools.partial` :ref:`to pass keywords
|
Use :func:`functools.partial` :ref:`to pass keyword arguments
|
||||||
<asyncio-pass-keywords>` to *func*.
|
<asyncio-pass-keywords>` to *func*.
|
||||||
|
|
||||||
.. method:: loop.remove_signal_handler(sig)
|
.. method:: loop.remove_signal_handler(sig)
|
||||||
|
@ -996,11 +996,52 @@ Executing code in thread or process pools
|
||||||
The *executor* argument should be an :class:`concurrent.futures.Executor`
|
The *executor* argument should be an :class:`concurrent.futures.Executor`
|
||||||
instance. The default executor is used if *executor* is ``None``.
|
instance. The default executor is used if *executor* is ``None``.
|
||||||
|
|
||||||
Use :func:`functools.partial` :ref:`to pass keywords
|
Example::
|
||||||
<asyncio-pass-keywords>` to *func*.
|
|
||||||
|
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.
|
This method returns a :class:`asyncio.Future` object.
|
||||||
|
|
||||||
|
Use :func:`functools.partial` :ref:`to pass keyword arguments
|
||||||
|
<asyncio-pass-keywords>` to *func*.
|
||||||
|
|
||||||
.. versionchanged:: 3.5.3
|
.. versionchanged:: 3.5.3
|
||||||
:meth:`loop.run_in_executor` no longer configures the
|
:meth:`loop.run_in_executor` no longer configures the
|
||||||
``max_workers`` of the thread pool executor it creates, instead
|
``max_workers`` of the thread pool executor it creates, instead
|
||||||
|
|
|
@ -109,50 +109,89 @@ To actually run a coroutine asyncio provides three main mechanisms:
|
||||||
Awaitables
|
Awaitables
|
||||||
==========
|
==========
|
||||||
|
|
||||||
We say that an object is an *awaitable* object if it can be used
|
We say that an object is an **awaitable** object if it can be used
|
||||||
in an :keyword:`await` expression.
|
in an :keyword:`await` expression. Many asyncio APIs are designed to
|
||||||
|
accept awaitables.
|
||||||
|
|
||||||
|
There are three main types of *awaitable* objects:
|
||||||
|
**coroutines**, **Tasks**, and **Futures**.
|
||||||
|
|
||||||
|
|
||||||
.. rubric:: Coroutines and Tasks
|
.. rubric:: Coroutines
|
||||||
|
|
||||||
Python coroutines are *awaitables*::
|
Python coroutines are *awaitables* and therefore can be awaited from
|
||||||
|
other coroutines::
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
async def nested():
|
async def nested():
|
||||||
return 42
|
return 42
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
# Will print "42":
|
# Nothing happens if we just call "nested()".
|
||||||
print(await nested())
|
# (a coroutine object is created but not awaited)
|
||||||
|
nested()
|
||||||
|
|
||||||
|
# Let's do it differently now and await it:
|
||||||
|
print(await nested()) # will print "42".
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
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*: an object returned by calling a
|
||||||
|
*coroutine function*.
|
||||||
|
|
||||||
|
asyncio also supports legacy :ref:`generator-based
|
||||||
|
<asyncio_generator_based_coro>` coroutines.
|
||||||
|
|
||||||
|
|
||||||
|
.. rubric:: Tasks
|
||||||
|
|
||||||
*Tasks* are used to schedule coroutines *concurrently*.
|
*Tasks* are used to schedule coroutines *concurrently*.
|
||||||
See the previous :ref:`section <coroutine>` for an introduction
|
|
||||||
to coroutines and tasks.
|
|
||||||
|
|
||||||
Note that in this documentation the term "coroutine" can be used for
|
When a coroutine is wrapped into a *Task* with functions like
|
||||||
two closely related concepts:
|
:func:`asyncio.create_task` the coroutine is automatically
|
||||||
|
scheduled to run soon::
|
||||||
|
|
||||||
* a *coroutine function*: an :keyword:`async def` function;
|
import asyncio
|
||||||
|
|
||||||
* a *coroutine object*: object returned by calling a
|
async def nested():
|
||||||
*coroutine function*.
|
return 42
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
# Schedule nested() to run soon concurrently
|
||||||
|
# with "main()".
|
||||||
|
task = asyncio.create_task(nested())
|
||||||
|
|
||||||
|
# "task" can now be used to cancel "nested()", or
|
||||||
|
# can simply be awaited to wait until it is complete:
|
||||||
|
await task
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
|
|
||||||
|
|
||||||
.. rubric:: Futures
|
.. rubric:: Futures
|
||||||
|
|
||||||
There is a dedicated section about the :ref:`asyncio Future object
|
A :class:`Future` is a special **low-level** awaitable object that
|
||||||
<asyncio-futures>`, but the concept is fundamental to asyncio so
|
represents an **eventual result** of an asynchronous operation.
|
||||||
it needs a brief introduction in this section.
|
|
||||||
|
When a Future object is *awaited* it means that the coroutine will
|
||||||
|
wait until the Future is resolved in some other place.
|
||||||
|
|
||||||
A Future is a special **low-level** awaitable object that represents
|
|
||||||
an **eventual result** of an asynchronous operation.
|
|
||||||
Future objects in asyncio are needed to allow callback-based code
|
Future objects in asyncio are needed to allow callback-based code
|
||||||
to be used with async/await.
|
to be used with async/await.
|
||||||
|
|
||||||
Normally, **there is no need** to create Future objects at the
|
Normally **there is no need** to create Future objects at the
|
||||||
application level code.
|
application level code.
|
||||||
|
|
||||||
Future objects, sometimes exposed by libraries and some asyncio
|
Future objects, sometimes exposed by libraries and some asyncio
|
||||||
APIs, should be awaited::
|
APIs, can be awaited::
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
await function_that_returns_a_future_object()
|
await function_that_returns_a_future_object()
|
||||||
|
@ -163,6 +202,9 @@ APIs, should be awaited::
|
||||||
some_python_coroutine()
|
some_python_coroutine()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
A good example of a low-level function that returns a Future object
|
||||||
|
is :meth:`loop.run_in_executor`.
|
||||||
|
|
||||||
|
|
||||||
Running an asyncio Program
|
Running an asyncio Program
|
||||||
==========================
|
==========================
|
||||||
|
@ -192,8 +234,8 @@ Creating Tasks
|
||||||
|
|
||||||
.. function:: create_task(coro, \*, name=None)
|
.. function:: create_task(coro, \*, name=None)
|
||||||
|
|
||||||
Wrap the *coro* :ref:`coroutine <coroutine>` into a Task and
|
Wrap the *coro* :ref:`coroutine <coroutine>` into a :class:`Task`
|
||||||
schedule its execution. Return the Task object.
|
and schedule its execution. Return the Task object.
|
||||||
|
|
||||||
If *name* is not ``None``, it is set as the name of the task using
|
If *name* is not ``None``, it is set as the name of the task using
|
||||||
:meth:`Task.set_name`.
|
:meth:`Task.set_name`.
|
||||||
|
@ -259,17 +301,17 @@ Sleeping
|
||||||
Running Tasks Concurrently
|
Running Tasks Concurrently
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
.. awaitablefunction:: gather(\*fs, loop=None, return_exceptions=False)
|
.. awaitablefunction:: gather(\*aws, loop=None, return_exceptions=False)
|
||||||
|
|
||||||
Run :ref:`awaitable objects <asyncio-awaitables>` in the *fs*
|
Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
|
||||||
sequence *concurrently*.
|
sequence *concurrently*.
|
||||||
|
|
||||||
If any awaitable in *fs* is a coroutine, it is automatically
|
If any awaitable in *aws* is a coroutine, it is automatically
|
||||||
scheduled as a Task.
|
scheduled as a Task.
|
||||||
|
|
||||||
If all awaitables are completed successfully, the result is an
|
If all awaitables are completed successfully, the result is an
|
||||||
aggregate list of returned values. The order of result values
|
aggregate list of returned values. The order of result values
|
||||||
corresponds to the order of awaitables in *fs*.
|
corresponds to the order of awaitables in *aws*.
|
||||||
|
|
||||||
If *return_exceptions* is ``True``, exceptions are treated the
|
If *return_exceptions* is ``True``, exceptions are treated the
|
||||||
same as successful results, and aggregated in the result list.
|
same as successful results, and aggregated in the result list.
|
||||||
|
@ -279,7 +321,7 @@ Running Tasks Concurrently
|
||||||
If ``gather`` is *cancelled*, all submitted awaitables
|
If ``gather`` is *cancelled*, all submitted awaitables
|
||||||
(that have not completed yet) are also *cancelled*.
|
(that have not completed yet) are also *cancelled*.
|
||||||
|
|
||||||
If any Task or Future from the *fs* sequence is *cancelled*, it is
|
If any Task or Future from the *aws* sequence is *cancelled*, it is
|
||||||
treated as if it raised :exc:`CancelledError` -- the ``gather()``
|
treated as if it raised :exc:`CancelledError` -- the ``gather()``
|
||||||
call is **not** cancelled in this case. This is to prevent the
|
call is **not** cancelled in this case. This is to prevent the
|
||||||
cancellation of one submitted Task/Future to cause other
|
cancellation of one submitted Task/Future to cause other
|
||||||
|
@ -329,13 +371,13 @@ Running Tasks Concurrently
|
||||||
Shielding Tasks From Cancellation
|
Shielding Tasks From Cancellation
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
.. awaitablefunction:: shield(fut, \*, loop=None)
|
.. awaitablefunction:: shield(aw, \*, loop=None)
|
||||||
|
|
||||||
Protect an :ref:`awaitable object <asyncio-awaitables>`
|
Protect an :ref:`awaitable object <asyncio-awaitables>`
|
||||||
from being :meth:`cancelled <Task.cancel>`.
|
from being :meth:`cancelled <Task.cancel>`.
|
||||||
|
|
||||||
*fut* can be a coroutine, a Task, or a Future-like object. If
|
*aw* can be a coroutine, a Task, or a Future-like object. If
|
||||||
*fut* is a coroutine it is automatically scheduled as a Task.
|
*aw* is a coroutine it is automatically scheduled as a Task.
|
||||||
|
|
||||||
The statement::
|
The statement::
|
||||||
|
|
||||||
|
@ -367,12 +409,12 @@ Shielding Tasks From Cancellation
|
||||||
Timeouts
|
Timeouts
|
||||||
========
|
========
|
||||||
|
|
||||||
.. coroutinefunction:: wait_for(fut, timeout, \*, loop=None)
|
.. coroutinefunction:: wait_for(aw, timeout, \*, loop=None)
|
||||||
|
|
||||||
Wait for the *fut* :ref:`awaitable <asyncio-awaitables>`
|
Wait for the *aw* :ref:`awaitable <asyncio-awaitables>`
|
||||||
to complete with a timeout.
|
to complete with a timeout.
|
||||||
|
|
||||||
If *fut* is a coroutine it is automatically scheduled as a Task.
|
If *aw* is a coroutine it is automatically scheduled as a Task.
|
||||||
|
|
||||||
*timeout* can either be ``None`` or a float or int number of seconds
|
*timeout* can either be ``None`` or a float or int number of seconds
|
||||||
to wait for. If *timeout* is ``None``, block until the future
|
to wait for. If *timeout* is ``None``, block until the future
|
||||||
|
@ -387,7 +429,7 @@ Timeouts
|
||||||
The function will wait until the future is actually cancelled,
|
The function will wait until the future is actually cancelled,
|
||||||
so the total wait time may exceed the *timeout*.
|
so the total wait time may exceed the *timeout*.
|
||||||
|
|
||||||
If the wait is cancelled, the future *fut* is also cancelled.
|
If the wait is cancelled, the future *aw* is also cancelled.
|
||||||
|
|
||||||
The *loop* argument is deprecated and scheduled for removal
|
The *loop* argument is deprecated and scheduled for removal
|
||||||
in Python 4.0.
|
in Python 4.0.
|
||||||
|
@ -415,22 +457,22 @@ Timeouts
|
||||||
# timeout!
|
# timeout!
|
||||||
|
|
||||||
.. versionchanged:: 3.7
|
.. versionchanged:: 3.7
|
||||||
When *fut* is cancelled due to a timeout, ``wait_for`` waits
|
When *aw* is cancelled due to a timeout, ``wait_for`` waits
|
||||||
for *fut* to be cancelled. Previously, it raised
|
for *aw* to be cancelled. Previously, it raised
|
||||||
:exc:`asyncio.TimeoutError` immediately.
|
:exc:`asyncio.TimeoutError` immediately.
|
||||||
|
|
||||||
|
|
||||||
Waiting Primitives
|
Waiting Primitives
|
||||||
==================
|
==================
|
||||||
|
|
||||||
.. coroutinefunction:: wait(fs, \*, loop=None, timeout=None,\
|
.. coroutinefunction:: wait(aws, \*, loop=None, timeout=None,\
|
||||||
return_when=ALL_COMPLETED)
|
return_when=ALL_COMPLETED)
|
||||||
|
|
||||||
Run :ref:`awaitable objects <asyncio-awaitables>` in the *fs*
|
Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
|
||||||
sequence concurrently and block until the condition specified
|
sequence concurrently and block until the condition specified
|
||||||
by *return_when*.
|
by *return_when*.
|
||||||
|
|
||||||
If any awaitable in *fs* is a coroutine, it is automatically
|
If any awaitable in *aws* is a coroutine, it is automatically
|
||||||
scheduled as a Task.
|
scheduled as a Task.
|
||||||
|
|
||||||
Returns two sets of Tasks/Futures: ``(done, pending)``.
|
Returns two sets of Tasks/Futures: ``(done, pending)``.
|
||||||
|
@ -471,12 +513,12 @@ Waiting Primitives
|
||||||
|
|
||||||
Usage::
|
Usage::
|
||||||
|
|
||||||
done, pending = await asyncio.wait(fs)
|
done, pending = await asyncio.wait(aws)
|
||||||
|
|
||||||
|
|
||||||
.. function:: as_completed(fs, \*, loop=None, timeout=None)
|
.. function:: as_completed(aws, \*, loop=None, timeout=None)
|
||||||
|
|
||||||
Run :ref:`awaitable objects <asyncio-awaitables>` in the *fs*
|
Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
|
||||||
set concurrently. Return an iterator of :class:`Future` objects.
|
set concurrently. Return an iterator of :class:`Future` objects.
|
||||||
Each Future object returned represents the earliest result
|
Each Future object returned represents the earliest result
|
||||||
from the set of the remaining awaitables.
|
from the set of the remaining awaitables.
|
||||||
|
@ -486,7 +528,7 @@ Waiting Primitives
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
for f in as_completed(fs):
|
for f in as_completed(aws):
|
||||||
earliest_result = await f
|
earliest_result = await f
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
|
@ -679,6 +721,52 @@ Task Object
|
||||||
A Task is *done* when the wrapped coroutine either returned
|
A Task is *done* when the wrapped coroutine either returned
|
||||||
a value, raised an exception, or the Task was cancelled.
|
a value, raised an exception, or the Task was cancelled.
|
||||||
|
|
||||||
|
.. method:: result()
|
||||||
|
|
||||||
|
Return the result of the Task.
|
||||||
|
|
||||||
|
If the Task is *done*, the result of the wrapped coroutine
|
||||||
|
is returned (or if the coroutine raised an exception, that
|
||||||
|
exception is re-raised.)
|
||||||
|
|
||||||
|
If the Task has been *cancelled*, this method raises
|
||||||
|
a :exc:`CancelledError` exception.
|
||||||
|
|
||||||
|
If the Task's result isn't yet available, this method raises
|
||||||
|
a :exc:`InvalidStateError` exception.
|
||||||
|
|
||||||
|
.. method:: exception()
|
||||||
|
|
||||||
|
Return the exception of the Task.
|
||||||
|
|
||||||
|
If the wrapped coroutine raised an exception that exception
|
||||||
|
is returned. If the wrapped coroutine returned normally
|
||||||
|
this method returns ``None``.
|
||||||
|
|
||||||
|
If the Task has been *cancelled*, this method raises a
|
||||||
|
:exc:`CancelledError` exception.
|
||||||
|
|
||||||
|
If the Task isn't *done* yet, this method raises an
|
||||||
|
:exc:`InvalidStateError` exception.
|
||||||
|
|
||||||
|
.. method:: add_done_callback(callback, *, context=None)
|
||||||
|
|
||||||
|
Add a callback to be run when the Task is *done*.
|
||||||
|
|
||||||
|
This method should only be used in low-level callback-based code.
|
||||||
|
|
||||||
|
See the documentation of :meth:`Future.add_done_callback`
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
.. method:: remove_done_callback(callback)
|
||||||
|
|
||||||
|
Remove *callback* from the callbacks list.
|
||||||
|
|
||||||
|
This method should only be used in low-level callback-based code.
|
||||||
|
|
||||||
|
See the documentation of :meth:`Future.remove_done_callback`
|
||||||
|
for more details.
|
||||||
|
|
||||||
.. method:: get_stack(\*, limit=None)
|
.. method:: get_stack(\*, limit=None)
|
||||||
|
|
||||||
Return the list of stack frames for this Task.
|
Return the list of stack frames for this Task.
|
||||||
|
|
Loading…
Reference in New Issue