On Mon, Oct 31, 2016 at 1:30 PM, Yury Selivanov <[email protected]>
wrote:

> Guido,
>
> I’m with Andrew on this one.
>

And the reason is the misbehavior of get_event_loop(), right? (See below.)


> > On Oct 31, 2016, at 10:27 AM, Guido van Rossum <[email protected]> wrote:
> >
> > I would suggest different guidelines for libraries than for
> > applications: Libraries should be robust and always store their own
> > loop. This is how asyncio itself works and how aiohttp (and other
> > libraries you name) work. Their test suite (like asyncio's) should
> > enforce this.
>
> >  But applications (and fledgling libraries may do this too) should be
> > allowed to assume a simpler model of the world: use coroutines (async
> > def, await) for everything, never store the loop, happily use
> > get_event_loop() when you really need it. And really, you should only
> > need it for run_in_executor(). If you find yourself using call_later()
> > you probably haven't quite figured out how to use coroutines properly.
>
> I don’t think people will follow this advice, because any application code
> can one day be refactored to become reusable (a library).  That’s why I
> write my asyncio code defensively, passing the loop explicitly.  This is
> probably the only aspect about asyncio I don’t like.  This is the main
> complaint about asyncio that we hear *repeatedly* from all kinds of users.
>
> The core reason causing all these problems is that get_event_loop is
> weakly defined.  It doesn’t always return the current loop when called from
> a coroutine.  It might return the wrong one, that just happens to be the
> “default”.
>

OK, I think I am seeing the problem now.


> I know that you defend the current behaviour by saying that people should
> only have one loop per process.  But some people have many in one process.
> That’s why we design libraries to handle the loop explicitly — that ensures
> that the library will work regardless of what get_event_loop returns.
>
> The result is that all asyncio libraries accept the “loop” parameter in
> their public APIs. All of them are architected to pass the loop explicitly
> internally.  And then, the asyncio end users aren’t sure how to use
> asyncio.  Python docs recommend (sometimes indirectly) to pass the loop
> explicitly.   Libraries and frameworks recommend that as well.
>

That's still a docs problem (many stdlib functions/methods have optional
parameters that are almost always left None).


> The end result of this is that asyncio programs always care “too much”
> about the loop: mange it, store references to it, explicitly pass it to
> coroutines.  This makes asyncio code harder to understand to both advanced
> and beginner users.
>

Right.


> My opinion on this:
>
> 1. We need to fix “get_event_loop” to return the *current* event loop when
> called from within a coroutine:
>
>   async def coro():
>      loop = asyncio.get_event_loop()
>
> This is something we can easily implement, because coroutines are *always*
> running under some event loop.
>

I now agree.


> 2. We should explain asyncio library authors that it is better to “hide”
> the loop from the high-level API.  The high level API should only consist
> of coroutines, that don’t have a “loop” parameter at all.  Because
> get_event_loop is guaranteed to always return the correct loop, it will be
> safe to use it.
>
> So instead of:
>
>   async def main(loop):
>      db = asyncpg.connect(…, loop=loop)
>   loop = asyncio.get_event_loop()
>   loop.run_until_complete(main(loop))
>
> people will always write this:
>
>   async def main():
>      db = asyncpg.connect(…)
>   loop = asyncio.get_event_loop()
>   loop.run_until_complete(main())
>

I think my (feeble) point is that we could recommend this even without
changing get_event_loop(), because the situation where get_event_loop()
returns the wrong loop is perverse. Unfortunately we've gone down this path
too long, so e.g. testing habits have developed that require explicitly
passing the loop. :-( So I agree we should fix #1.


> 3. Docs should say that the event loop is a low-level API.  As you said,
> if you call “loop.call_soon” from your application code, then something is
> wrong.
>
> If we can shift asyncio libraries to be designed around coroutine-first
> API, we can safely start caring much less about the loop.  We will only use
> it to run the main() coroutine of the program.
>
> This is something that curio does right — the event loop is what runs the
> program, but the end user knows pretty much nothing about it. Coroutines
> just work, because curio provides a *reliable* way for getting the
> *current* loop from within a running coroutine context.
>
> This is a fully backwards compatible change.  We even have a PR to do
> this: https://github.com/python/asyncio/pull/355.  That PR might need
> another review pass, but the idea is there.
>
> Thank you,
> Yury
>
>
Thanks! We can fix this in 3.6b4.

-- 
--Guido van Rossum (python.org/~guido)

Reply via email to