Open 60717714-ac02-4c78-a5e0-6f0d36b9c456 opened 6 years ago
Hi Yury,
As discussed, below is a very rough outline of a proposed TOC for an asyncio tutorial. No content has been written yet (only what you see below). I think we should nail down the TOC first.
Asyncio Tutorial \================
Proposed Table of Contents:
Why asyncio?
The difference between functions and async def
functions
async def
functions, compare to def
functions. await <x>
is an expression, and you can
use it in most places any other expression can be used.How to run async def
functions
async def
functions
can call other functions, and other async def
functions using
await
, but also, (b) how to "get started" with the first
async def
function? Answer: run the event loop.asyncio.run()
, in particular running an async def main()
function, which itself can call others.Dealing with concurrent functions
async def
function, but you don't
want to wait for it? Answer: create a "task" for it.gather
or wait()
Case Study: chat server/client (my proposal)
send
and recv
in separate tasksrun()
functionI like this, great job!
Couple of thoughts on how we should organize this:
I think we should stick to your structure and push things to docs.python.org as soon as every next section is somewhat ready.
Every big section should probably have its own page, linking prev/next tutorial pages.
I'd organize the tutorial in a dedicated directory like "Doc/library/asyncio-tutorial/". Context: I wanted to reorganize all current "Doc/library/asyncio*.rst" files under one dir too, but decided to keep the existing file structure to avoid breaking links to the docs from SO/google). We shouldn't repeat that mistake again.
BTW, maybe we should consider using the new iPythonn async repl: https://blog.jupyter.org/ipython-7-0-async-repl-a35ce050f7f7 What do you think about that?
Some comments on the proposed TOC:
- Reason #1: thread safety by not using threads at all.
- Reason #2: very many concurrent socket connections, which threads make cumbersome.
This section is super important to get right, as I see people ask the "why and where should I use asyncio" _all _the _time_. So I'll expand on this section in a detail.
Reason #1 and #2 are correct, but I think we should really focus on making #1 comprehensive and clear:
async/await makes all context switches visible; that makes it easy to spot race conditions and reason about your code (think about ORMs that can make 100s of queries to render one web page); you've likely seen https://glyph.twistedmatrix.com/2014/02/unyielding.html
in general, all datastructures are safe for async (we cannot say same for threads);
an async/await library means that it's safe to use it in concurrent async/await code (you can never be sure if some library is thread-safe, even if it claims that);
language constructs like 'async for' and 'async with' enable structured concurrency;
And on #2:
high-throughput IO or 1000s of long-living connections are only doable with asyncio
if you don't need to scale your code right now but might need in near future investing in async/await is wise
- How to run
async def
functions
- point out there are two different issues: (a)
async def
functions can call other functions, and otherasync def
functions usingawait
, but also, (b) how to "get started" with the firstasync def
function? Answer: run the event loop.
Just a quick note: I'd try to not mention the low-level loop APIs as long as possible (e.g. no loop.run_until_complete() etc).
Right, we'll need to update the asyncio-task.rst file. I think we'll collapse first two section into one ("Coroutines" and "Awaitables" into "Awaitables") and link the tutorial from that new section.
- Case Study: chat server/client (my proposal) [..]
- server uses streams API
Yay for streams!
[..]
- client implementation has some options:
I never use tkinter myself :( I remember trying to use it and it didn't work on my macOS. So I'd try to either:
- I think we should stick to your structure and push things to docs.python.org as soon as every next section is somewhat ready.
Ok. I'll get a PR going for the start page of the tutorial.
- Every big section should probably have its own page, linking prev/next tutorial pages.
- I'd organize the tutorial in a dedicated directory like "Doc/library/asyncio-tutorial/".
Agree.
BTW, maybe we should consider using the new iPythonn async repl: https://blog.jupyter.org/ipython-7-0-async-repl-a35ce050f7f7 What do you think about that?
I saw Matthias' tweets about that recently too. It's cool! but...for teaching purposes it's not great to introduce a whole new complex tool (ipython) to explain a different complex tool (asyncio). My experience is that *every* single new thing that is mentioned adds cognitive load for learners. For this tutorial my feeling is to keep as much to "ordinary" Python stuff as possible, i.e., stdlib.
Just a quick note: I'd try to not mention the low-level loop APIs as long as possible (e.g. no loop.run_until_complete() etc).
For sure, I agree with you 100% on this. But I find it hard to do as soon as I have to make a real thing. I think you're right that we focus initially on only high-level stuff first (and for most of the tut). That is doable.
I think we'll collapse first two section into one ("Coroutines" and "Awaitables" into "Awaitables") and link the tutorial from that new section.
ok
Yay for streams! I never use tkinter myself :( I remember trying to use it and it didn't work on my macOS. So I'd try to either:
- build a simple browser app (that would require us to implement HTTP 0.9 which can be fun);
- build a terminal app;
- use iPython repl to connect to our asyncio server (might end up being more complicated than the first two options).
I too have bashed my head for many hours over the years trying to get Tkinter to work on Mac, but a lot of work has gone into this recently and the newer (release) Python's have bundled Tk 8.6: https://www.python.org/download/mac/tcltk/ (this is what learners will prob use on Mac)
Tkinter gets a bad rap, but it's really quite powerful--and portable. Runs great on a Raspberry Pi for example.
Noticing your hesitation towards tkinter ;) , I spent a few hours on Sunday sketching out my "chat server/client" idea a little more, using Tkinter for the client UI:
(Notice especially in the README all the different aspects of asyncio, streams etc. that we would be able to cover and explain with an actual use-case. THESE are the kinds of tricky things people desperately want help with.)
It's still rough obviously (I can prob reduce the total LOC footprint by 20% & I'm sure you can improve on some parts) but I just wanted to show you something runnable you can prod and poke to give a concrete idea of what I'm suggesting. It works on Windows, should work on Linux but I haven't tested yet.
My proposal is that we slowly build up towards this, starting with the "hello world" simple case (asyncio.run calling main() which prints out "hello world" or something), and then adding the necessary features, piece by piece, with commentary along the way on what each piece does, and why it is done in a particular way. (I specifically like to write like this: simplistic case first, and then improve incrementally)
I fully realise that this case study implementation might look weird and ugly, and we don't really want to mention threads at all, and we don't want to explicitly refer to the loop, or create a Future instance, etc., but this is the kind of case study that will give people guidance on how to handle these *actual problems* that they are going to come across.
If you have a look and still don't want to go this way, that's ok, I'm happy to go with a different suggestion.
I too have bashed my head for many hours over the years trying to get Tkinter to work on Mac, but a lot of work has gone into this recently and the newer (release) Python's have bundled Tk 8.6: https://www.python.org/download/mac/tcltk/ (this is what learners will prob use on Mac)
I've tried to run it and here's what I have on my system:
~/d/t/chat (master) » python3.7 client.py
Traceback (most recent call last):
File "client.py", line 7, in <module>
from tkinter import *
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 36, in <module>
import _tkinter # If this fails your Python may not be configured for Tk
ModuleNotFoundError: No module named '_tkinter'
How about we write the tutorial and implement terminal clients first. Then we can have two branches of the tutorial -- one implementing a Tk client, one implementing a web client?
A CLI client is a necessary step along the way anyway, so that sounds good by me.
You suggested:
I'd organize the tutorial in a dedicated directory like "Doc/library/asyncio-tutorial/"
I had a look at the source tree, there is an existing "howto" directory; do you still prefer your suggestion of using "Doc/library/" over something like "Doc/howto/asyncio.rst"?
I set up a basic structure under "Doc/library/asyncio-tutorial" as suggested, and opened a PR to show you how that looks. When I make more progress on a section, I'll post an update here.
I tested the Python 3.7.0 release version for Mac, the download called "macOS 64-bit installer" with checksum ae0717a02efea3b0eb34aadc680dc498 on this page:
https://www.python.org/downloads/release/python-370/
I downloaded, installed that on a mac, and the chat client app launched no problem. (I added a screenshot to my github repo readme).
Your error "ModuleNotFoundError: No module named '_tkinter'" suggests that the python you were using is a different one, because in the release download, Tk 8.6.8 is bundled and the _tkinter module was built against it and must exist.
Anyway, I just wanted to check that it does work on mac :)
Yury, based on the file paths, you appear to be running a MacPorts python3.7. Like many other third-party distributors (but unlike the python.org installers), MacPorts separates Tkinter support into a separately-installable component. Try:
port install py37-tkinter
Yury, based on the file paths, you appear to be running a MacPorts python3.7. Like many other third-party distributors (but unlike the python.org installers), MacPorts separates Tkinter support into a separately-installable component. Try:
Thanks, Ned! Yeah, I know why my python37 doesn't have Tk and how to fix it. It's just I don't think the tutorial should require some component that we know is missing when python is installed through certain channels (with default flags/config).
I've added a few ideas for items in the "cookbook" page, which you'll see in the PR. If anyone has suggestions for more or better cookbook entries (recipes?), feel free to mention here or in the PR, I check both places. I expect to get more time to work on this next weekend, so it would be great to get ideas and reviews in during the week.
A quick note to say I have not abandoned this, it's just that life got complicated for me in late 2018. I intend to pick up progress again within the next month or two.
That was an long two months, apologies. I've made some fixes based on review comments and cleaned up some more of the code samples. The primary outstanding pieces are the client component of the chat application case study, and the GUI integration section of the client case study.
FYI I'm going to be using the 3rd-party prompt-toolkit for the chat client. (The server depends only on asyncio only). I put several hours research into finding a way for the CLI chat client to be not terrible, but it gets very complicated trying to manage stdin and stdout with asyncio. OTOH prompt-toolkit just gives us exactly what we need, and the code looks short, neat and easy to understand. I hope that's ok (that I'll be mentioning a 3rd party lib in the tutorial).
I'm removing the GUI section of the chat case study. Yury was right, it's not going to add anything useful. The CLI chat client will work well because prompt-toolkit has actual support for asyncio. Tkinter does not, and I think it'll be better to add a GUI section to this tutorial only once Tkinter gets first-class support for asyncio.
So, I basically stalled on this work because I was waiting for changes in asyncio to settle down. In particular task groups and PEP 654 exception groups. After PEP 654 in 3.11, there will be more changes to asyncio to make use of it yes?
Ok I see they're already in #90908
I doubt that asyncio will ever "settle down". :-) But anyway, I am currently working on docs for task groups.
The PR https://github.com/python/cpython/pull/9748 seems stuck and the PR is very large, it would be better to split it up so that things get merged as ready.
@CAM-Gerlach Are you interested in taking over this? I and hopefully @gvanrossum can volunteer to review the docs updates. It would be great to have this in 3.12.
Anyone is more than welcome to take it over. Unfortunately I haven't been able to find bandwidth to pick this up again.
This looks like a pretty big project, and as a disclaimer I have very little subject matter expertise or experience (coming from scientific Python, when I work with parallelism is almost invariably of the "embarrassingly parallel" compute-bound variety, and consequently use of asyncio
is virtually unheard of in most of my discipline). Like with sqlite3
, the other individual module I've spent a relatively disproportionate amount of time helping with the docs on, its something where most of what I do know comes from reviewing people's docs PRs on the subject (since at least in my domains of research, scientists tend to have a strong aversion to SQL-type databases as a data storage mechanism).
This can actually be a significant benefit to helping ensure the docs, especially a generally beginner-focused tutorial, is easy to understand and follow, and doesn't embed assumptions that can be really easy to forget about as a subject matter expert (as I do myself when I am in those shoes). However, for the parts that aren't already written, I'm going to need knowledge help actually drafting something, at which point I can learn the material myself and then make it better (which is typically what I am strongest at anyway). The sprints next week might be a great time to work on it if others have some bandwidth to help guide me and answer my inevitable questions, assuming I am not called away to more immediately pressing tasks.
My initial high level comments is based on the outline above, as well as skimming through the PR. Right now, it looks like much if not most of this content, aside from the "case study", is actually not quite a tutorial at all, at least as currently framed:
asyncio
.Following this lens, each of these can be independent pages, or at least section of existing pages, and organized appropriately with other content that has a similar goal (and, ideally, in the order readers tend to refer to them, i.e. essentially the inverse of what they are now—i.e. something like Tutorial, How-To, Reference, Explanation (rather than the current opposite). However, that provides a great framework for splitting up the existing PR into more manageable and independent chunks that we could complete, revise and merge in series or in parallel, rather than a single large, interdependent set of documents. Its also a great opportunity for us to continue gaining more practical experience applying the Diataxis principles, as part of a broader process of of expanding and revising our documentation to better serve users' needs.
I'm happy to answer all sorts of questions, both in person during the sprint and online afterwards.
I can't tell from skimming this issue how much was already written. Assuming not much has been written, my recommendation would be to start small, trying to get a PR merged that adds a very skinny tutorial that doesn't cover most topics (even important ones). That way we can hopefully spread the effort, perhaps similarly to how the Python tutorial grew from utter basics to what it is now, through many contributions.
I hope we can make this a showcase for Diataxis (I hope you did the workshop, I didn't, alas, but I've skimmed the docs about it).
I'm happy to answer all sorts of questions, both in person during the sprint and online afterwards.
You've been really helpful answering my questions so far (including those I didn't know ask, but appreciated having answered) so I'm happy to have you on board!
I can't tell from skimming this issue how much was already written.
It wasn't formally linked here, but it seems from the corresponding PR, #9748 , that the great majority it was already written, except for the chat client CLI tutorial (aside from just a stub), and a few specific how-tos in the "cookbook" which were marked as TODO.
Assuming not much has been written, my recommendation would be to start small, trying to get a PR merged that adds a very skinny tutorial that doesn't cover most topics (even important ones).
Since most of it is already written, what I had been thinking might work best pulling out each atomic top-level component of that, doing the necessary work to get it ready to go and submitting each for review as an independent PR (either as its own document, or as a section of an existing one as appropriate). We could simply defer the client tutorial for now as well as the still-TODO how-to items, at least until after this was all completed. Right now, the existing PR is fairly well enough organized into components that it shouldn't be too difficult to pull apart, with a bit of thought ahead of time and appropriate revisions.
I hope we can make this a showcase for Diataxis
Indeed, I hope so too—though, our primary goal is to serve users, with Diataxis being an effective means to that end.
I hope you did the workshop
I'd hope so too, considering I was one of the organizers :laughing: and I also have some (very helpful) practical experience applying it alongside Ezio and Erlend to the sqlite3
module docs (with the tutorial being what we ended up having to spend the most time on, and making the most improvements too).
I've skimmed the docs about it
The docs are good on their own, but as I found out along with Ezio and Erlend, we only started to truly understand and appreciate Diataxis once we dug in and really started putting it into practice.
Unfortunately, I didn't get the chance to make much progress on this at the sprint as I was very bogged down on other things. I do have a fair number of urgent things to get out of the way first, but hopefully this should go fairly well once I get to it, since most of the work is already done in the PR, with the most of the remainder being right within my wheelhouse.
We should also consider adding some async generators examples in tutorial with current best practices.
Changing the status of this issue to TODO. The original PR was closed. Thanks @cjrh for your work on that (:wave: hope all is well). This would be a good in-person effort at a future sprint.
There is current interest in #124668 for additional examples. See https://github.com/python/cpython/issues/124668#issuecomment-2418943439 for additional context.
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields: ```python assignee = None closed_at = None created_at =
labels = ['3.8', 'type-feature', '3.7', 'docs', 'expert-asyncio']
title = 'Asyncio Tutorial'
updated_at =
user = 'https://github.com/cjrh'
```
bugs.python.org fields:
```python
activity =
actor = 'cjrh'
assignee = 'docs@python'
closed = False
closed_date = None
closer = None
components = ['Documentation', 'asyncio']
creation =
creator = 'cjrh'
dependencies = []
files = []
hgrepos = []
issue_num = 34831
keywords = ['patch']
message_count = 14.0
messages = ['326628', '326665', '326789', '326977', '327266', '327271', '327275', '327284', '327286', '328201', '333088', '345661', '345755', '346039']
nosy_count = 6.0
nosy_names = ['asvetlov', 'cjrh', 'Elvis.Pranskevichus', 'docs@python', 'yselivanov', 'willingc']
pr_nums = ['9748']
priority = 'normal'
resolution = None
stage = 'patch review'
status = 'open'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue34831'
versions = ['Python 3.7', 'Python 3.8']
```