I found asyncio really daunting. Writing about it in Fluent Python was by far the hardest part in the book -- and my goal was really modest, just explain some very, very basic examples. I was glad to have Victor Stinner review that chapter in my book, so no major problems were reporded by readers so far, and several readers have written nice things about that chapter.
BTW, if any of you would like a courtesy copy of the e-book, let me know and I'll ask O'Reilly. I also believe we should have some basic asyncio HTTP support in the standard library. Nothing as fancy or full-featured as aiohttp -- which is great -- but just some basic functionality so that the documentation can offer better examples, closer to what most users will want to do with asyncio (which is not dealing with raw sockets or inventing their own network protocols). Cheers, Luciano On Sun, Oct 30, 2016 at 5:02 PM, Yury Selivanov <[email protected]> wrote: > >> On Oct 30, 2016, at 2:42 PM, Guido van Rossum <[email protected]> wrote: >> >> On Sun, Oct 30, 2016 at 11:27 AM, Yury Selivanov <[email protected]> >> wrote: >>> >>>> On Oct 30, 2016, at 1:58 PM, Guido van Rossum <[email protected]> wrote: >>>> >>>> Regarding the documentation, I doubt we can get it in shape just by >>>> filing issues. We should really just have a tutorial written by >>>> someone with a good understanding of asyncio and writing skills. >>> >>> Yeah, I agree. I don’t want to promise anything, but this is something I >>> wanted to do for a long time now. If no one tackles this in the next >>> couple of months, I’ll try to start the process myself. >>> >>>> >>>> I wonder how enlightening the chapter by A. Jesse Jiryu Davis here >>>> really is for beginners? >>>> http://aosabook.org/en/500L/a-web-crawler-with-asyncio-coroutines.html >>>> (my name is on it because I wrote the original code -- Jesse wrote all >>>> the text and rewrote the code several times over :-). >>> >>> I think it’s an excellent piece, but maybe it’s a tad more detailed than >>> what we need for asyncio docs. IMO the opening page of asyncio docs should >>> cover the following: >>> >>> 1. Why asyncio - one paragraph. >>> 2. What is event loop - one p. >>> 3. What is a coroutine - one p. >>> 4. asyncio essentials: get_event_loop, run_until_complete, close, >>> create_task, gather, open_connection, start_server. >> >> IMO this focuses on the loop too much. We should explain more on how >> to use coroutines. >> >>> 5. Advanced topics: should I pass event loop explicitly? etc >>> >>> Speaking about APIs and passing working with the loop. One thing that >>> people find attractive in curio is that it doesn’t really focus on the >>> loop. You start your initial coroutine with the loop (called “kernel” in >>> curio) and that’s it. >> >> Isn't the equivalent in asyncio just as easy? Start your initial >> coroutine with asyncio.get_event_loop().run_until_complete() and >> that's it. > > You also should call loop.close(), which adds try..except around your > loop.run_until_complete code. You also should await on > loop.shutdown_asyncgens in 3.6. Those things add up. > >> >> How does curio open a connection? How does it start serving? Asyncio >> requires the loop for those. Is the loop implicit in curio? > > Well, in asyncio you can just “await asyncio.open_connection()” without > passing a loop explicitly. > > And that’s how curio does this too - you always use coroutines to do > *everything*. There is API to reliably get the loop that runs your current > code (‘asyncio.get_event_loop’ should be fixed a little bit in my opinion, > but we already had this discussion here: > https://github.com/python/asyncio/pull/355). > > So in curio the loop is implicit, and I think it’s actually a good design > decision. Because the “root” of your program is always a coroutine, and you > can reliably get the current loop, you don’t need to pass it around > explicitly. > > I think that even with the current asyncio design we should aim for the > similar user experience. We already have “asyncio.open_connection” that > doesn’t require the loop. We can add “asyncio.run_in_executor” (as opposed > to “loop.run_in_executor") so that there is one less API that requires you to > care about the loop. > >> >>> What if we could do the following: >>> >>> 1. Provide an “asyncio.run(coro)” function to run your "main()” coroutine >>> program and take care of everything loop-related for you. >> >> So that's just asyncio.get_event_loop().run_until_complete(coro)? I >> worry that the shortness of the call will make people call this from >> inside coroutines or callbacks. >> >>> “asyncio.run” should create the loop, run the coroutine, cleanup >>> asynchronous generators and unfinished tasks, close the loop etc. >> >> I'd be less opposed if it was called asyncio.main(). That makes it >> clear that you run this one, inside your own main. > > I’d be OK with “asyncio.main". > >> >>> 2. There are some APIs that can’t be called without a loop: >>> run_in_executor, sockets ops etc. What if we add >>> “asyncio.run_in_background” coroutine that would get the event loop and >>> call run_in_executor on it? >> >> Well in theory you could add asyncio.foo() calls for every loop >> method. I'm not sure I'm excited about that. Nor about using different >> names. > > Yeah, let’s forget about using different names — a bad idea. > > I’ve just looked through events.py. I think we may only need to add > “asyncio.run_in_executor(func)”, and maybe “asyncio.create_task(coroutine)” > functions. With that it should be possible to have almost the same > “loopless” experience in asyncio as with curio: > > async def program(): > await asyncio.run_in_executor(func) > await asyncio.open_connection(…) > task = asyncio.create_task(…) > asyncio.main(program()) > > >> >>> 3. In 3.7 we can add a Socket-like object with asynchronous “recv”, “send”, >>> etc coroutines. Turns out people want this, as it’s more convenient to use >>> than loop.sock_sendall. Using streams is of course better, but sometimes >>> you want to quickly make your existing program async without a full rewrite. >> >> I'd question *why* people want sockets. > > Just more familiar API I think. > >> Perhaps it's really just a >> wrapper around a StreamReader/Writer pair? Can a curio socket wrap a >> subprocess? A pipe? A tty device? > > Curio socket is a very thin wrapper on top of python socket and whatever > non-blocking stuff python allows to do. The API is essentially the same, > with all blocking methods made coroutines. > > I think people find Curio streams a bit more intuitive because they are just > one object, not a pair of reader/writer. > > Yury -- Luciano Ramalho | Author of Fluent Python (O'Reilly, 2015) | http://shop.oreilly.com/product/0636920032519.do | Technical Principal at ThoughtWorks | Twitter: @ramalhoorg
