> On Oct 30, 2016, at 2:42 PM, Guido van Rossum <gu...@python.org> wrote:
> 
> On Sun, Oct 30, 2016 at 11:27 AM, Yury Selivanov <yseliva...@gmail.com> wrote:
>> 
>>> On Oct 30, 2016, at 1:58 PM, Guido van Rossum <gu...@python.org> 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

Reply via email to