[issue26969] ascynio should provide a policy to address pass-loop-everywhere problem

Yury Selivanov report at bugs.python.org
Tue May 10 16:15:41 EDT 2016


Yury Selivanov added the comment:

> Yury, what do you think of this yourself? Maybe you can explain it better
than Ilya?

TBH, I don't fully understand Ilya's case with threads, synchronous coroutines, possible deadlocks etc.  So I'll just explain what I would want out of this.

I don't like a few aspects of the current design of 'get_event_loop'.  Mainly because it creates an event loop implicitly, or it can just fail with a RuntimeError under some conditions.  When one has a few event loops, implicitly called 'get_event_loop' from Future and other asyncio functions won't work correctly.  IMO, this is something that we at least should try to fix (even though it's not an idiomatic use case for asyncio).

I now think that we don't need a new function for getting the currently running event loop.  Instead we can try to improve the `get_event_loop()` function a little.

The core idea is to add a thread-local object `running_loop`, which will point to the currently running event loop in the current thread.  And `Loop._run` method will set/reset a reference to the loop to `running_loop`.

`get_event_loop()` will then try to use the `running_loop` object first, and if nothing is there, fall back to its current implementation.

Now, this is a point where everything becomes complicated. To quote myself,--"Yes, the patch part is easy",--I don't think it is that easy anymore ;)

Currently, event loops are decoupled from policies.  This means that we can't make loops to use some hidden shared thread-local object (`running_loop`) that policies and loops will work with.  There has to be another new public policy APIs that loops will use, for instance: 'set_running_event_loop()'.  This won't be the first case of event loop policy APIs being called from event loops -- another example is the `get_child_watcher` method.

With this new method, `Loop._run` will then look like this:

  def _run(self):
      policy = get_event_loop_policy()
      policy.set_running_event_loop(self)
      try:
         ... # current Loop._run implementation
      finally:
          policy.set_running_event_loop(None)

`policy.set_running_event_loop` call would raise a RuntimeError if it's called if another event loop is currently running.

And the `get_event_loop()` function will look like this:

  def get_event_loop():
      policy = get_event_loop_policy()
      loop = policy._get_running_event_loop()
      if loop is not None:
          return loop
      # ... current get_event_loop implementation

So it all boils down to:

1. Adding a new policy API 'set_running_event_loop'.

2. Updating 'get_event_loop' to return the currently running event loop if it's available, or else resorting to its current behaviour.

With this change it will be completely safe to use "get_event_loop" from running coroutines or just about any code that runs in a context of an event loop.

----------

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue26969>
_______________________________________


More information about the Python-bugs-list mailing list