-
-
Notifications
You must be signed in to change notification settings - Fork 32.7k
gh-138072: Small clarifications and phrasing improvements to asyncio HOWTO #138073
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
anordin95
wants to merge
9
commits into
python:main
Choose a base branch
from
anordin95:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+24
−11
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
07d5a0a
- Small clarifications and phrasing improvements
anordin95 34f496f
nit
anordin95 b189b94
Apply suggestions from code review
anordin95 f97bfb6
clarify event loops when multi threading.
anordin95 a389c09
nit
anordin95 2831208
Update Doc/howto/a-conceptual-overview-of-asyncio.rst
anordin95 274c727
nit
anordin95 12d6e35
nit
anordin95 176814e
phrasing for threads & event loops.
anordin95 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -42,11 +42,11 @@ 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 behind the scenes managing resources. | ||||||
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. | ||||||
Some jobs are added directly by you, and some indirectly by :mod:`!asyncio`. | ||||||
|
@@ -60,7 +60,7 @@ This process repeats indefinitely with the event loop cycling endlessly | |||||
onwards. | ||||||
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 | ||||||
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 | ||||||
could hog control and leave the other jobs to starve, rendering the overall | ||||||
|
@@ -171,14 +171,16 @@ Roughly speaking, :ref:`tasks <asyncio-task-obj>` are coroutines (not coroutine | |||||
functions) tied to an event loop. | ||||||
A task also maintains a list of callback functions whose importance will become | ||||||
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 | ||||||
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 | ||||||
associating the task with the event loop for you. As such, there's no need | ||||||
to specify the event loop. | ||||||
:mod:`!asyncio` automatically associates tasks with the event loop for you. | ||||||
Typically there's only one event loop, so that's quite straightforward. | ||||||
It's uncommon, but some applications use multithreading and :mod:`!asyncio` | ||||||
together, where there's one event loop per thread, stored in thread-local | ||||||
storage. | ||||||
|
||||||
:: | ||||||
|
||||||
|
@@ -251,6 +253,10 @@ different ways:: | |||||
In a crucial way, the behavior of ``await`` depends on the type of object | ||||||
being awaited. | ||||||
|
||||||
^^^^^^^^^^ | ||||||
await task | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
^^^^^^^^^^ | ||||||
|
||||||
Awaiting a task will cede control from the current task or coroutine to | ||||||
the event loop. | ||||||
In the process of relinquishing control, a few important things happen. | ||||||
|
@@ -282,6 +288,10 @@ This is a basic, yet reliable mental model. | |||||
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. | ||||||
|
||||||
^^^^^^^^^^^^^^^ | ||||||
await coroutine | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
^^^^^^^^^^^^^^^ | ||||||
|
||||||
**Unlike tasks, awaiting a coroutine does not hand control back to the event | ||||||
loop!** | ||||||
Wrapping a coroutine in a task first, then awaiting that would cede | ||||||
|
@@ -348,8 +358,10 @@ The design intentionally trades off some conceptual clarity around usage of | |||||
``await`` for improved performance. | ||||||
Each time a task is awaited, control needs to be passed all the way up the | ||||||
call stack to the event loop. | ||||||
That might sound minor, but in a large program with many ``await``'s and a deep | ||||||
callstack that overhead can add up to a meaningful performance drag. | ||||||
Then, the event loop needs to manage its internal state and work through | ||||||
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 meaningful performance drag. | ||||||
|
||||||
------------------------------------------------ | ||||||
A conceptual overview part 2: the nuts and bolts | ||||||
|
@@ -365,7 +377,8 @@ and how to make your own asynchronous operators. | |||||
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 | ||||||
resume a coroutine. | ||||||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"stored in thread-local" is unnecesary implemenetation detail for the reader, just per thread seems sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See discussion here: #138073 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd also be OK with just "per thread". But, I don't totally understand the rationale to clarify thread-locality here -- what was wrong with the original wording?