[Python-ideas] How the heck does async/await work in Python 3.5
Terry Reedy
tjreedy at udel.edu
Thu Feb 25 01:49:56 EST 2016
On 2/24/2016 8:05 PM, Nick Coghlan wrote:
> On 25 February 2016 at 06:57, Terry Reedy <tjreedy at udel.edu> wrote:
>> On 2/24/2016 4:59 AM, Paul Moore wrote:
>>>
>>> On 24 February 2016 at 02:37, Terry Reedy <tjreedy at udel.edu> wrote:
>>>>
>>>>
>>>> In this essay, Brett says that asyncio added an event loop to Python. It
>>>> did, but it was the second. The tk event loop was added about 20 years
>>>> ago
>>>> with tkinter.
>>>
>>> One of the things I would love to see (but don't have the time to work
>>> on) is a GUI event loop based around async/await. It would be a very
>>> useful example to make it clear to people that async/await isn't just
>>> about network protocols.
>>
>> Aiming at this was part of the point of my closing comment about adapting
>> generators to the tk mainloop callback interface. The next step would be to
>> do the same for awaitables. However, I need more study of the details of
>> asyncio and the async/await protocol.
>
> Letting GUI event loops take over running awaitables is part of the
> rationale for the event loop management features in asyncio:
> https://docs.python.org/3/library/asyncio-eventloops.html
One issue I have with asyncio.base_events.BaseEventLoop is that it is
not a base event loop. It is a derived network IO event loop which
could have been called NetworkIOEventLoop. It 'subclasses' the true
base event loop by containment. The latter, call it MinimalEventLoop,
comprises the run and call methods listed in
https://docs.python.org/3/library/asyncio-eventloop.html ('loop', not
'loops', as above) and perhaps the task methods. In any case, it is
only about 1/4 the derived class. Integrating tkinter's event loop
only involves this subset. I might have found it easier to think about
this if there were a separate base class.
> Having an event loop interface adapter in the stdlib tk modules that
> can be used with asyncio.set_event_loop()
My memory is that any replacement event loop is expected to be a full
implmentation of the network io loop, so one cannot just make a gui loop
that works with coroutines.
> would provide a much clearer
> demonstration of the full power of that approach than the current
> "*nix selectors vs Windows IOCP" capability (the latter is useful, but
> doesn't cover the "integration with an existing 3rd party event loop"
> use case).
I believe the selector and proactor subclass only the network part of
BaseEventLoop. A cross-platform gui might to modify the event part of
either. I guess the following should work
---
EventLoop = select_event_loop(OS, needs)
class TkEventLoop:
# modify loop methods as needed
set_event_loop(TkEventLoop)
---
The heart of BaseEventLoop is .run_forever, and the heart of this is
while True:
self._run_once()
if self._stopping:
break
The tk equivalent of _run_once, call it tkupdate, is tkinter.Tk().update
("Enter event loop until all pending events have been processed by Tcl.
[and return]).
If 'while True' is kept as the master loop, it might be sufficient to
add a call to tkupdate either before or after the _run_once_ call. I
will have to try this and see what happens.
This would be easiest to do is there were a self.updater attribute,
initially None, which a user could set to an external update function to
be called once in each loop.
The opposite approach, far more difficult, would be to replace the
Python while loop with the tk loop and change other methods as needed.
Here is where having a giant class is awkward. There are 13 private
attributes. Do the network methods depend on these? Another issue is
that the the tk loop object is accessible from python only indirectly.
At this point, I am wondering whether it would be easier to forget the
asynio network io loop and write from scratch a tkinter-based loop class
that has the minimum needed to work with async and await code. But what
is that minimum? PEP 492 "assumes that the asynchronous tasks are
scheduled and coordinated by an Event Loop similar to that of stdlib
module asyncio.events.AbstractEventLoop." However, AsstractEventLoop is
not that, but an abstract network/socket io event loop and a majority of
the methods cannot be needed for non-network, non-socket code.
Let me try again. What is the actual minimal event loop api required by
await?
--
Terry Jan Reedy
More information about the Python-ideas
mailing list