Terry J. Reedy added the comment:

> wasting battery power ?!  We live in slightly different computing universes 
> ;-).  But I get the point.  The last two files I uploaded use call_later and 
> I should stick with that.  I should also add a note that the innermost 
> asyncio loop function sleeps when there is nothing to do and that the tk 
> updater wakes it up, if necessary, to check for gui events even when there 
> are none.  Updater is polling rather than interrupt based.  Or in other 
> words, it interrupts asyncio to poll tk.

I should also say that the update interval is passed in to the class so one can 
make an instance-specific tradeoff between overhead and responsiveness and 
display update frequency.  A read-only display might be updated just once a 
minute.

If loop.call_later(0.1, tk_update) is actually a problem on a system, then IDLE 
would likely be twice as bad, as it also has a busy loop in the user process, 
polling both the socket connection and calling tk update 20 times a second.  
There are also loops in the IDLE process.


I agree on the ideal solution and on the key component, which is to sleep until 
there is a ready Task or file event.  _run_once does this in the select call by 
adjusting the timeout to the minimum time to the next ready task (possibly 0).

Tcl has such a component, with the addition of simultaneously waiting for 
window events -- but it only only includes file events on unix.  (It took a 
brave and talented group to try to reconcile the Unix and Windows models.)

Here is a simplified Python version of Tcl_DoOneEvent. 
http://www.tcl.tk/man/tcl8.6/TclLib/DoOneEvent.htm  

Tcl has window, file, timer, and idle events.  Window events include user key 
and mouse events and other from the graphics system.  The first three types all 
go in one ready queue. Idle events are those that affect what the user sees on 
the screen and go in a separate, lower-priority queue.

def do_one_event(sleep_ok):
    if ready:
        process(ready.pop())
        return True
    load_ready()
    if ready:
        process(ready.pop())
        return True
    if idle:
        for event in idle:
            process(event)
        return True
    if sleep_ok:
        sleep_until_event()  # the hard part
        load_ready()
        process(ready.pop())
        return True
    else:
        return False

def load_ready():
    # In some unspecified order
    ready.extend(get_window_events)  # graphics system
    ready.extend(get_file_events)  # select
    ready.extend(get_timer_events)  # priority queue pops

Update processes all events available without sleeping. 
http://www.tcl.tk/man/tcl8.6/TclCmd/update.htm
Mainloop continues (with sleeps) while there are toplevels and not stopped.

def update():
    while(do_one_event(sleep_ok=False)): pass

def mainloop():
    while toplevels and not stop:
        do_one_event()

Sleep_ok is actually a dont_sleep bit flag. DoOneEvent has other flags to 
select which types of event to process.  Hence

def update_idletasks()  # all currently ready
    do_one_event(dont_sleep | idletasks)

It is possible for the idle queue to get starved for attention.  Hence the 
existence of update_idletasks and recommendations to call it in certain 
situations.


It would also be possible to call (from Python, via tcl) 
do_one_event(dont_sleep | gui_events) IF it were known that a gui event was 
ready to be retrieved.  It is knowing that, without polling in a 'busy loop' 
that is hard to impossible.  If it were possible, an extra call to do idletasks 
would also be needed..

In summary, I see this as a situation where practicality beats a possibly 
unattainable purity.

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue27546>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to