[Python-ideas] Add hooks to asyncio lifecycle

Yury Selivanov yselivanov.ml at gmail.com
Tue Jun 5 10:17:05 EDT 2018


Hi Michel,

Yes, theoretically, it's possible to try to change an event loop
policy while an event loop is running, but I've yet to see a library
(or user code) that tries to do that (it's pointless anyways). There
are libraries like uvloop that tell their users to explicitly install
a special policy *before* they run their code, but that's about it.
The only use case for policies is allowing to plug in a custom event
loop implementation.

The current policies implementation, as well as "get_event_loop()" and
"get_running_loop()" functions, is already very complex.  For example,
I tried to add rudimentary support for "os.fork()" in 3.7 and failed,
because there are too many things that can go wrong.  Therefore
without a *very* clear case for adding hooks, I'm -1 on further
extending and complicating policies API (or any related APIs).

I actually want to propose to reduce policies API surface by
deprecating and then removing "set_child_watcher()" methods.  Besides,
there are many other higher priority To-Do items for asyncio in 3.8,
like implementing Trio's nursery-like objects and cancellation scopes
or fixing tracebacks in Tasks.

That said, the above is my "IMO".  And in your email you haven't
actually provided clear scenarios that could be solved by adding
"event loop hooks" to asyncio.  So I have a few questions for you:

- Do you have real-life examples of libraries that abuse policies in
some weird ways?
- Are those libraries popular?
- What's the actual problem they try to solve by using policies?
- What problem are you trying to solve in your code that uses policies?
- Why do you think this isn't a documentation/tutorial issue?
- Can you list 2-3 clear examples where having hooks would benefit an
average asyncio user?

Thank you,
Yury

On Tue, Jun 5, 2018 at 8:48 AM Michel Desmoulin
<desmoulinmichel at gmail.com> wrote:
>
> After years of playing with asyncio, I'm still having a harder time
> using it than any other async architecture around. There are a lot of
> different reasons for it, but this mail want to address one particular one:
>
> The event loop and policy can be tweaked at any time, by anyone.
>
> Now, it's hard enough to have to deal, manually, with a low-level event
> loop. But having it exposed that much, and it being that flexible means
> any code can just do whatever it wants with it, and make a mess.
>
> Several things in particular, comes to mind:
>
> - Changing the event loop policy
> - Changing the event loop
> - Spawning a new loop
> - Starting the loop
> - Stopping the loop
> - Closing the loop
>
> Now, if you want to make any serious project with it, you currently have
> to guard against all of those, especially if you want to have proper
> cleanup code, good error message and a decent debugging experience.
>
> I tried to do it for one year, and currently, it's very hard. You have a
> lot of checks to make, redundantly in a lot of places. Some things can
> only be done by providing a custom event policy/loop yourself, and, of
> course, expecting (aka documenting and praying) that it's used.
>
> For a lot of things, when it breaks, the people that haven't read the
> doc in depth will have a hard time to understand the problem after the fact.
>
> Sometimes, it's just that your code use somebody else code that is not
> here to read your doc anymore. Now you have to check their code to
> understand what they are doing that breaks your expectations about the
> loop / policy or workflow.
>
> Barring the creating of an entire higher level framework that everybody
> will agree on using and that makes messing up way harder, we can improve
> this situation by adding hooks to those events.
>
> I hence propose to add:
>
> - asyncio.on_change_policy(cb:Callable[[EventLoopPolicy,
> EventLoopPolicy], EventLoopPolicy])
>
> - asyncio.on_set_event_loop(cb:Callable[[EventLoop, EventLoop], EventLoop])
>
> - asyncio.on_create_event_loop(cb:Callable[[EventLoop], EventLoop])
>
> - EventLoop.on_start(cb:Callable[EventLoop])
>
> - EventLoop.on_stop(cb:Awaitable[EventLoop])
>
> - EventLoop.on_close(cb:Callable[EventLoop])
>
> - EventLoop.on_set_debug_mode(cb:Callable[[loop]])
>
> This would allow to implement safer, more robust and easier to debug
> code. E.G:
>
> - you can raise a warning stating that if somebody changes the event
> policy, it must inherit from your custom one or deal with disabled features
>
> - you can raise an exception on loop swap and forbid it, saying that
> your small script doesn't support it yet so that it's easy to understand
> the limit of your code
>
> - you can hook on the event loop life cycle to automatically get on
> board, or run clean up code, starting logging, warn that you were
> supposed to start the loop yourself, etc
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/



-- 
         Yury


More information about the Python-ideas mailing list