-
-
Notifications
You must be signed in to change notification settings - Fork 32.8k
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
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: Peter Bierma <[email protected]>
Co-authored-by: Peter Bierma <[email protected]>
: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 |
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?
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.
This paragraph states asyncio
automatically associates tasks with the event loop so you, the user, don't need to specify the loop in the asyncio.create_task
constructor (nor are you even allowed to). The "per thread" part implies there can be multiple event loops (via multithreading) in the same memory space.
I think it's quite natural to then wonder how tasks will be associated with event loops when there are multiple event loops to choose from. And how you, the user, could manage which loop a task is assigned to. I see that as an easy way for the reader to get confused. The point of this article is to be explanatory.
While, yes, it is an implementation detail, it's not some arcane, fragile aspect. It's a fundamental design pattern exposed by the OS. And, it appears this usage of thread-local hasn't changed in the 12 years that asyncio
has been around.
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.
Thread locality is an implementation detail and should stay as an implementation detail, -1 for adding this.
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.
Yes, that is largely what you wrote the first time around. The logical gap I highlighted would still exist and potentially confuse readers. I agree, implementation details should generally be kept in the code, but not always. Sparsely and judiciously exposing broad ideas can ultimately create more explanatory and helpful docs, as opposed to making many vague, abstract statements, especially since this is a HOWTO, not reference, doc. Could you clarify some of the reasoning behind why you feel this way?
Like I mentioned in the prior PR, perhaps you can see how it's difficult to productively engage with this style of feedback and discussion?
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.
Alex, I sympathize with thread-locality being quite confusing, but I'm going to side with Kumar here. asyncio
really isn't about multithreading at all, and as you said, this is an explanatory HOWTO article. We should try to avoid bringing up niche use-cases that make the reader think "oh, asyncio
and multithreading are friends, let's do that more".
As a compromise for now, would you mind reverting these changes and putting them in a follow-up PR so we can argue about it there? The rest of the changes in this PR look good to me, and it would better for those to not be blocked by discussions about this.
(We really do value your article as a contribution, please don't take this the wrong way!)
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.
Mhm fair enough :). Will do.
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: #138200
@@ -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 comment
The reason will be displayed to describe this comment to others. Learn more.
await task | |
Awaiting Tasks |
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 prefer the original for a few reasons.
The titles come from the references made in the broader await
section intro.
They offer a nudge to think about await
beyond just the keyword itself and emphasize how the object await
applies to is fundamentally important to the operation.
And they fit more naturally in the broader table of contents:

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.
await task | |
Awaiting tasks |
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.
Hugo's suggestion would be my preference here and below.
@@ -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 comment
The reason will be displayed to describe this comment to others. Learn more.
await coroutine | |
Awaiting Coroutines |
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.
Use sentence case for headers:
https://devguide.python.org/documentation/style-guide/#capitalization
await coroutine | |
Awaiting coroutines |
(We could also fix "A Conceptual Overview of asyncio" -> "A conceptual overview of asyncio" and "Event Loop" -> "Event loop".)

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.
FYI I fixed the other sentence-case examples you mentioned. But, I left await task
and await coroutine
for the reasons described here: #138073 (comment)
: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 |
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.
Thread locality is an implementation detail and should stay as an implementation detail, -1 for adding this.
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
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.
With Hugo's suggested title changes, I am fine with the current state of this document.
Let's strive to keep this conceptual overview fairly high-level. The doc's purpose should stay focused on an overview and avoid going too far into a technical deep dive.
I think all requested changes have been addressed in this PR, besides modifications to the For ease of reference, the style guide says: "In the Python documentation, the use of sentence case in section titles is preferable, but consistency within a unit is more important than following this rule.". Additionally, I think the use of "preferable" above implies there can be reasonable cases that ignore this guidance. I personally prefer the titles as they are now, for the reasons enumerated here. With that in mind, I wonder if leaving them as is would be amenable for folks? |
Please do rename them to "Awaiting tasks" and "Awaiting coroutines".
That's referring to the The next sentence of the devguide:
![]() Well, the rest is already in sentence case, let's stick to it. |
For reference, I interpreted the style guide as providing some leeway and more generally I think it can make sense to sometimes ignore strict adherence to style guides, in this case, for the sake of content/flow. Either way, it seems my arguments fell short and failed to sway minds! I'll go ahead and change the section titles as requested. P.S. The same idea regarding |
📚 Documentation preview 📚: https://cpython-previews--138073.org.readthedocs.build/en/138073/howto/a-conceptual-overview-of-asyncio.html#a-conceptual-overview-of-asyncio