mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-138072: Small clarifications and phrasing improvements to asyncio HOWTO (#138073)
* - Small clarifications and phrasing improvements * nit * Apply suggestions from code review Co-authored-by: Peter Bierma <zintensitydev@gmail.com> * clarify event loops when multi threading. * nit * Update Doc/howto/a-conceptual-overview-of-asyncio.rst Co-authored-by: Peter Bierma <zintensitydev@gmail.com> * nit * nit * phrasing for threads & event loops. * revert changes to event-loop/thread discussion. * sentence case consistencty. * slight re-arrange. * Sentence case consistency. * tweak language. non-negligible --------- Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
This commit is contained in:
parent
96f496a949
commit
b3b63e8d6d
1 changed files with 25 additions and 14 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
.. _a-conceptual-overview-of-asyncio:
|
.. _a-conceptual-overview-of-asyncio:
|
||||||
|
|
||||||
****************************************
|
****************************************
|
||||||
A Conceptual Overview of :mod:`!asyncio`
|
A conceptual overview of :mod:`!asyncio`
|
||||||
****************************************
|
****************************************
|
||||||
|
|
||||||
This :ref:`HOWTO <how-tos>` article seeks to help you build a sturdy mental
|
This :ref:`HOWTO <how-tos>` article seeks to help you build a sturdy mental
|
||||||
|
|
@ -37,15 +37,15 @@ In part 1, we'll cover the main, high-level building blocks of :mod:`!asyncio`:
|
||||||
the event loop, coroutine functions, coroutine objects, tasks, and ``await``.
|
the event loop, coroutine functions, coroutine objects, tasks, and ``await``.
|
||||||
|
|
||||||
==========
|
==========
|
||||||
Event Loop
|
Event loop
|
||||||
==========
|
==========
|
||||||
|
|
||||||
Everything in :mod:`!asyncio` happens relative to the event loop.
|
Everything in :mod:`!asyncio` happens relative to the event loop.
|
||||||
It's the star of the show.
|
It's the star of the show, but prefers to work behind the scenes, managing
|
||||||
|
and coordinating resources.
|
||||||
It's like an orchestra conductor.
|
It's like an orchestra conductor.
|
||||||
It's behind the scenes managing resources.
|
|
||||||
Some power is explicitly granted to it, but a lot of its ability to get things
|
Some power is explicitly granted to it, but a lot of its ability to get things
|
||||||
done comes from the respect and cooperation of its worker bees.
|
done comes from the respect and cooperation of its band members.
|
||||||
|
|
||||||
In more technical terms, the event loop contains a collection of jobs to be run.
|
In more technical terms, the event loop contains a collection of jobs to be run.
|
||||||
Some jobs are added directly by you, and some indirectly by :mod:`!asyncio`.
|
Some jobs are added directly by you, and some indirectly by :mod:`!asyncio`.
|
||||||
|
|
@ -59,7 +59,7 @@ This process repeats indefinitely, with the event loop cycling endlessly
|
||||||
onwards.
|
onwards.
|
||||||
If there are no more jobs pending execution, the event loop is smart enough to
|
If there are no more jobs pending execution, the event loop is smart enough to
|
||||||
rest and avoid needlessly wasting CPU cycles, and will come back when there's
|
rest and avoid needlessly wasting CPU cycles, and will come back when there's
|
||||||
more work to be done.
|
more work to be done, such as when I/O operations complete or timers expire.
|
||||||
|
|
||||||
Effective execution relies on jobs sharing well and cooperating; a greedy job
|
Effective execution relies on jobs sharing well and cooperating; a greedy job
|
||||||
could hog control and leave the other jobs to starve, rendering the overall
|
could hog control and leave the other jobs to starve, rendering the overall
|
||||||
|
|
@ -170,14 +170,14 @@ Roughly speaking, :ref:`tasks <asyncio-task-obj>` are coroutines (not coroutine
|
||||||
functions) tied to an event loop.
|
functions) tied to an event loop.
|
||||||
A task also maintains a list of callback functions whose importance will become
|
A task also maintains a list of callback functions whose importance will become
|
||||||
clear in a moment when we discuss :keyword:`await`.
|
clear in a moment when we discuss :keyword:`await`.
|
||||||
The recommended way to create tasks is via :func:`asyncio.create_task`.
|
|
||||||
|
|
||||||
Creating a task automatically schedules it for execution (by adding a
|
Creating a task automatically schedules it for execution (by adding a
|
||||||
callback to run it in the event loop's to-do list, that is, collection of jobs).
|
callback to run it in the event loop's to-do list, that is, collection of jobs).
|
||||||
|
The recommended way to create tasks is via :func:`asyncio.create_task`.
|
||||||
|
|
||||||
Since there's only one event loop (in each thread), :mod:`!asyncio` takes care of
|
Since there's only one event loop (in each thread), :mod:`!asyncio` takes
|
||||||
associating the task with the event loop for you. As such, there's no need
|
care of associating the task with the event loop for you.
|
||||||
to specify the event loop.
|
As such, there's no need to specify the event loop.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
|
@ -250,6 +250,10 @@ different ways::
|
||||||
In a crucial way, the behavior of ``await`` depends on the type of object
|
In a crucial way, the behavior of ``await`` depends on the type of object
|
||||||
being awaited.
|
being awaited.
|
||||||
|
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
Awaiting tasks
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Awaiting a task will cede control from the current task or coroutine to
|
Awaiting a task will cede control from the current task or coroutine to
|
||||||
the event loop.
|
the event loop.
|
||||||
In the process of relinquishing control, a few important things happen.
|
In the process of relinquishing control, a few important things happen.
|
||||||
|
|
@ -281,6 +285,10 @@ This is a basic, yet reliable mental model.
|
||||||
In practice, the control handoffs are slightly more complex, but not by much.
|
In practice, the control handoffs are slightly more complex, but not by much.
|
||||||
In part 2, we'll walk through the details that make this possible.
|
In part 2, we'll walk through the details that make this possible.
|
||||||
|
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
Awaiting coroutines
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
**Unlike tasks, awaiting a coroutine does not hand control back to the event
|
**Unlike tasks, awaiting a coroutine does not hand control back to the event
|
||||||
loop!**
|
loop!**
|
||||||
Wrapping a coroutine in a task first, then awaiting that would cede
|
Wrapping a coroutine in a task first, then awaiting that would cede
|
||||||
|
|
@ -347,8 +355,10 @@ The design intentionally trades off some conceptual clarity around usage of
|
||||||
``await`` for improved performance.
|
``await`` for improved performance.
|
||||||
Each time a task is awaited, control needs to be passed all the way up the
|
Each time a task is awaited, control needs to be passed all the way up the
|
||||||
call stack to the event loop.
|
call stack to the event loop.
|
||||||
That might sound minor, but in a large program with many ``await`` statements and a deep
|
Then, the event loop needs to manage its internal state and work through
|
||||||
call stack, that overhead can add up to a meaningful performance drag.
|
its processing logic to resume the next job.
|
||||||
|
That might sound minor, but in a large program with many ``await``\ s, that
|
||||||
|
overhead can add up to a non-negligible performance drag.
|
||||||
|
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
A conceptual overview part 2: the nuts and bolts
|
A conceptual overview part 2: the nuts and bolts
|
||||||
|
|
@ -364,7 +374,8 @@ and how to make your own asynchronous operators.
|
||||||
The inner workings of coroutines
|
The inner workings of coroutines
|
||||||
================================
|
================================
|
||||||
|
|
||||||
:mod:`!asyncio` leverages four components to pass around control.
|
:mod:`!asyncio` leverages four components of Python to pass
|
||||||
|
around control.
|
||||||
|
|
||||||
:meth:`coroutine.send(arg) <generator.send>` is the method used to start or
|
:meth:`coroutine.send(arg) <generator.send>` is the method used to start or
|
||||||
resume a coroutine.
|
resume a coroutine.
|
||||||
|
|
@ -448,9 +459,9 @@ That might sound odd to you. You might be thinking:
|
||||||
That causes the error: ``SyntaxError: yield from not allowed in a coroutine.``
|
That causes the error: ``SyntaxError: yield from not allowed in a coroutine.``
|
||||||
This was intentionally designed for the sake of simplicity -- mandating only
|
This was intentionally designed for the sake of simplicity -- mandating only
|
||||||
one way of using coroutines.
|
one way of using coroutines.
|
||||||
|
Despite that, ``yield from`` and ``await`` effectively do the same thing.
|
||||||
Initially ``yield`` was barred as well, but was re-accepted to allow for
|
Initially ``yield`` was barred as well, but was re-accepted to allow for
|
||||||
async generators.
|
async generators.
|
||||||
Despite that, ``yield from`` and ``await`` effectively do the same thing.
|
|
||||||
|
|
||||||
=======
|
=======
|
||||||
Futures
|
Futures
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue