Skip to content

Commit e247b46

Browse files
authored
bpo-33649: More improvements (GH-9439)
1 parent 8213ead commit e247b46

File tree

2 files changed

+176
-47
lines changed

2 files changed

+176
-47
lines changed

Doc/library/asyncio-eventloop.rst

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,7 @@ Watching file descriptors
755755
invoke *callback* with the specified arguments once *fd* is available for
756756
writing.
757757

758-
Use :func:`functools.partial` :ref:`to pass keywords
758+
Use :func:`functools.partial` :ref:`to pass keyword arguments
759759
<asyncio-pass-keywords>` to *func*.
760760

761761
.. method:: loop.remove_writer(fd)
@@ -969,7 +969,7 @@ Unix signals
969969
Raise :exc:`ValueError` if the signal number is invalid or uncatchable.
970970
Raise :exc:`RuntimeError` if there is a problem setting up the handler.
971971

972-
Use :func:`functools.partial` :ref:`to pass keywords
972+
Use :func:`functools.partial` :ref:`to pass keyword arguments
973973
<asyncio-pass-keywords>` to *func*.
974974

975975
.. method:: loop.remove_signal_handler(sig)
@@ -996,11 +996,52 @@ Executing code in thread or process pools
996996
The *executor* argument should be an :class:`concurrent.futures.Executor`
997997
instance. The default executor is used if *executor* is ``None``.
998998

999-
Use :func:`functools.partial` :ref:`to pass keywords
1000-
<asyncio-pass-keywords>` to *func*.
999+
Example::
1000+
1001+
import asyncio
1002+
import concurrent.futures
1003+
1004+
def blocking_io():
1005+
# File operations (such as logging) can block the
1006+
# event loop: run them in a thread pool.
1007+
with open('/dev/urandom', 'rb') as f:
1008+
return f.read(100)
1009+
1010+
def cpu_bound():
1011+
# CPU-bound operations will block the event loop:
1012+
# in general it is preferable to run them in a
1013+
# process pool.
1014+
return sum(i * i for i in range(10 ** 7))
1015+
1016+
async def main():
1017+
loop = asyncio.get_running_loop()
1018+
1019+
## Options:
1020+
1021+
# 1. Run in the default loop's executor:
1022+
result = await loop.run_in_executor(
1023+
None, blocking_io)
1024+
print('default thread pool', result)
1025+
1026+
# 2. Run in a custom thread pool:
1027+
with concurrent.futures.ThreadPoolExecutor() as pool:
1028+
result = await loop.run_in_executor(
1029+
pool, blocking_io)
1030+
print('custom thread pool', result)
1031+
1032+
# 3. Run in a custom process pool:
1033+
with concurrent.futures.ProcessPoolExecutor() as pool:
1034+
result = await loop.run_in_executor(
1035+
pool, cpu_bound)
1036+
print('custom process pool', result)
1037+
1038+
asyncio.run(main())
10011039

10021040
This method returns a :class:`asyncio.Future` object.
10031041

1042+
Use :func:`functools.partial` :ref:`to pass keyword arguments
1043+
<asyncio-pass-keywords>` to *func*.
1044+
10041045
.. versionchanged:: 3.5.3
10051046
:meth:`loop.run_in_executor` no longer configures the
10061047
``max_workers`` of the thread pool executor it creates, instead

Doc/library/asyncio-task.rst

Lines changed: 131 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -109,50 +109,89 @@ To actually run a coroutine asyncio provides three main mechanisms:
109109
Awaitables
110110
==========
111111

112-
We say that an object is an *awaitable* object if it can be used
113-
in an :keyword:`await` expression.
112+
We say that an object is an **awaitable** object if it can be used
113+
in an :keyword:`await` expression. Many asyncio APIs are designed to
114+
accept awaitables.
114115

116+
There are three main types of *awaitable* objects:
117+
**coroutines**, **Tasks**, and **Futures**.
115118

116-
.. rubric:: Coroutines and Tasks
117119

118-
Python coroutines are *awaitables*::
120+
.. rubric:: Coroutines
121+
122+
Python coroutines are *awaitables* and therefore can be awaited from
123+
other coroutines::
124+
125+
import asyncio
119126

120127
async def nested():
121128
return 42
122129

123130
async def main():
124-
# Will print "42":
125-
print(await nested())
131+
# Nothing happens if we just call "nested()".
132+
# (a coroutine object is created but not awaited)
133+
nested()
134+
135+
# Let's do it differently now and await it:
136+
print(await nested()) # will print "42".
137+
138+
asyncio.run(main())
139+
140+
.. important::
141+
142+
In this documentation the term "coroutine" can be used for
143+
two closely related concepts:
144+
145+
* a *coroutine function*: an :keyword:`async def` function;
146+
147+
* a *coroutine object*: an object returned by calling a
148+
*coroutine function*.
149+
150+
asyncio also supports legacy :ref:`generator-based
151+
<asyncio_generator_based_coro>` coroutines.
152+
153+
154+
.. rubric:: Tasks
126155

127156
*Tasks* are used to schedule coroutines *concurrently*.
128-
See the previous :ref:`section <coroutine>` for an introduction
129-
to coroutines and tasks.
130157

131-
Note that in this documentation the term "coroutine" can be used for
132-
two closely related concepts:
158+
When a coroutine is wrapped into a *Task* with functions like
159+
:func:`asyncio.create_task` the coroutine is automatically
160+
scheduled to run soon::
161+
162+
import asyncio
163+
164+
async def nested():
165+
return 42
133166

134-
* a *coroutine function*: an :keyword:`async def` function;
167+
async def main():
168+
# Schedule nested() to run soon concurrently
169+
# with "main()".
170+
task = asyncio.create_task(nested())
135171

136-
* a *coroutine object*: object returned by calling a
137-
*coroutine function*.
172+
# "task" can now be used to cancel "nested()", or
173+
# can simply be awaited to wait until it is complete:
174+
await task
175+
176+
asyncio.run(main())
138177

139178

140179
.. rubric:: Futures
141180

142-
There is a dedicated section about the :ref:`asyncio Future object
143-
<asyncio-futures>`, but the concept is fundamental to asyncio so
144-
it needs a brief introduction in this section.
181+
A :class:`Future` is a special **low-level** awaitable object that
182+
represents an **eventual result** of an asynchronous operation.
183+
184+
When a Future object is *awaited* it means that the coroutine will
185+
wait until the Future is resolved in some other place.
145186

146-
A Future is a special **low-level** awaitable object that represents
147-
an **eventual result** of an asynchronous operation.
148187
Future objects in asyncio are needed to allow callback-based code
149188
to be used with async/await.
150189

151-
Normally, **there is no need** to create Future objects at the
190+
Normally **there is no need** to create Future objects at the
152191
application level code.
153192

154193
Future objects, sometimes exposed by libraries and some asyncio
155-
APIs, should be awaited::
194+
APIs, can be awaited::
156195

157196
async def main():
158197
await function_that_returns_a_future_object()
@@ -163,6 +202,9 @@ APIs, should be awaited::
163202
some_python_coroutine()
164203
)
165204

205+
A good example of a low-level function that returns a Future object
206+
is :meth:`loop.run_in_executor`.
207+
166208

167209
Running an asyncio Program
168210
==========================
@@ -192,8 +234,8 @@ Creating Tasks
192234

193235
.. function:: create_task(coro, \*, name=None)
194236

195-
Wrap the *coro* :ref:`coroutine <coroutine>` into a Task and
196-
schedule its execution. Return the Task object.
237+
Wrap the *coro* :ref:`coroutine <coroutine>` into a :class:`Task`
238+
and schedule its execution. Return the Task object.
197239

198240
If *name* is not ``None``, it is set as the name of the task using
199241
:meth:`Task.set_name`.
@@ -259,17 +301,17 @@ Sleeping
259301
Running Tasks Concurrently
260302
==========================
261303

262-
.. awaitablefunction:: gather(\*fs, loop=None, return_exceptions=False)
304+
.. awaitablefunction:: gather(\*aws, loop=None, return_exceptions=False)
263305

264-
Run :ref:`awaitable objects <asyncio-awaitables>` in the *fs*
306+
Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
265307
sequence *concurrently*.
266308

267-
If any awaitable in *fs* is a coroutine, it is automatically
309+
If any awaitable in *aws* is a coroutine, it is automatically
268310
scheduled as a Task.
269311

270312
If all awaitables are completed successfully, the result is an
271313
aggregate list of returned values. The order of result values
272-
corresponds to the order of awaitables in *fs*.
314+
corresponds to the order of awaitables in *aws*.
273315

274316
If *return_exceptions* is ``True``, exceptions are treated the
275317
same as successful results, and aggregated in the result list.
@@ -279,7 +321,7 @@ Running Tasks Concurrently
279321
If ``gather`` is *cancelled*, all submitted awaitables
280322
(that have not completed yet) are also *cancelled*.
281323

282-
If any Task or Future from the *fs* sequence is *cancelled*, it is
324+
If any Task or Future from the *aws* sequence is *cancelled*, it is
283325
treated as if it raised :exc:`CancelledError` -- the ``gather()``
284326
call is **not** cancelled in this case. This is to prevent the
285327
cancellation of one submitted Task/Future to cause other
@@ -329,13 +371,13 @@ Running Tasks Concurrently
329371
Shielding Tasks From Cancellation
330372
=================================
331373

332-
.. awaitablefunction:: shield(fut, \*, loop=None)
374+
.. awaitablefunction:: shield(aw, \*, loop=None)
333375

334376
Protect an :ref:`awaitable object <asyncio-awaitables>`
335377
from being :meth:`cancelled <Task.cancel>`.
336378

337-
*fut* can be a coroutine, a Task, or a Future-like object. If
338-
*fut* is a coroutine it is automatically scheduled as a Task.
379+
*aw* can be a coroutine, a Task, or a Future-like object. If
380+
*aw* is a coroutine it is automatically scheduled as a Task.
339381

340382
The statement::
341383

@@ -367,12 +409,12 @@ Shielding Tasks From Cancellation
367409
Timeouts
368410
========
369411

370-
.. coroutinefunction:: wait_for(fut, timeout, \*, loop=None)
412+
.. coroutinefunction:: wait_for(aw, timeout, \*, loop=None)
371413

372-
Wait for the *fut* :ref:`awaitable <asyncio-awaitables>`
414+
Wait for the *aw* :ref:`awaitable <asyncio-awaitables>`
373415
to complete with a timeout.
374416

375-
If *fut* is a coroutine it is automatically scheduled as a Task.
417+
If *aw* is a coroutine it is automatically scheduled as a Task.
376418

377419
*timeout* can either be ``None`` or a float or int number of seconds
378420
to wait for. If *timeout* is ``None``, block until the future
@@ -387,7 +429,7 @@ Timeouts
387429
The function will wait until the future is actually cancelled,
388430
so the total wait time may exceed the *timeout*.
389431

390-
If the wait is cancelled, the future *fut* is also cancelled.
432+
If the wait is cancelled, the future *aw* is also cancelled.
391433

392434
The *loop* argument is deprecated and scheduled for removal
393435
in Python 4.0.
@@ -415,22 +457,22 @@ Timeouts
415457
# timeout!
416458

417459
.. versionchanged:: 3.7
418-
When *fut* is cancelled due to a timeout, ``wait_for`` waits
419-
for *fut* to be cancelled. Previously, it raised
460+
When *aw* is cancelled due to a timeout, ``wait_for`` waits
461+
for *aw* to be cancelled. Previously, it raised
420462
:exc:`asyncio.TimeoutError` immediately.
421463

422464

423465
Waiting Primitives
424466
==================
425467

426-
.. coroutinefunction:: wait(fs, \*, loop=None, timeout=None,\
468+
.. coroutinefunction:: wait(aws, \*, loop=None, timeout=None,\
427469
return_when=ALL_COMPLETED)
428470

429-
Run :ref:`awaitable objects <asyncio-awaitables>` in the *fs*
471+
Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
430472
sequence concurrently and block until the condition specified
431473
by *return_when*.
432474

433-
If any awaitable in *fs* is a coroutine, it is automatically
475+
If any awaitable in *aws* is a coroutine, it is automatically
434476
scheduled as a Task.
435477

436478
Returns two sets of Tasks/Futures: ``(done, pending)``.
@@ -471,12 +513,12 @@ Waiting Primitives
471513

472514
Usage::
473515

474-
done, pending = await asyncio.wait(fs)
516+
done, pending = await asyncio.wait(aws)
475517

476518

477-
.. function:: as_completed(fs, \*, loop=None, timeout=None)
519+
.. function:: as_completed(aws, \*, loop=None, timeout=None)
478520

479-
Run :ref:`awaitable objects <asyncio-awaitables>` in the *fs*
521+
Run :ref:`awaitable objects <asyncio-awaitables>` in the *aws*
480522
set concurrently. Return an iterator of :class:`Future` objects.
481523
Each Future object returned represents the earliest result
482524
from the set of the remaining awaitables.
@@ -486,7 +528,7 @@ Waiting Primitives
486528

487529
Example::
488530

489-
for f in as_completed(fs):
531+
for f in as_completed(aws):
490532
earliest_result = await f
491533
# ...
492534

@@ -679,6 +721,52 @@ Task Object
679721
A Task is *done* when the wrapped coroutine either returned
680722
a value, raised an exception, or the Task was cancelled.
681723

724+
.. method:: result()
725+
726+
Return the result of the Task.
727+
728+
If the Task is *done*, the result of the wrapped coroutine
729+
is returned (or if the coroutine raised an exception, that
730+
exception is re-raised.)
731+
732+
If the Task has been *cancelled*, this method raises
733+
a :exc:`CancelledError` exception.
734+
735+
If the Task's result isn't yet available, this method raises
736+
a :exc:`InvalidStateError` exception.
737+
738+
.. method:: exception()
739+
740+
Return the exception of the Task.
741+
742+
If the wrapped coroutine raised an exception that exception
743+
is returned. If the wrapped coroutine returned normally
744+
this method returns ``None``.
745+
746+
If the Task has been *cancelled*, this method raises a
747+
:exc:`CancelledError` exception.
748+
749+
If the Task isn't *done* yet, this method raises an
750+
:exc:`InvalidStateError` exception.
751+
752+
.. method:: add_done_callback(callback, *, context=None)
753+
754+
Add a callback to be run when the Task is *done*.
755+
756+
This method should only be used in low-level callback-based code.
757+
758+
See the documentation of :meth:`Future.add_done_callback`
759+
for more details.
760+
761+
.. method:: remove_done_callback(callback)
762+
763+
Remove *callback* from the callbacks list.
764+
765+
This method should only be used in low-level callback-based code.
766+
767+
See the documentation of :meth:`Future.remove_done_callback`
768+
for more details.
769+
682770
.. method:: get_stack(\*, limit=None)
683771

684772
Return the list of stack frames for this Task.

0 commit comments

Comments
 (0)