Message271421
> 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. |
|
Date |
User |
Action |
Args |
2016-07-27 00:36:26 | terry.reedy | set | recipients:
+ terry.reedy, gvanrossum, Ludovic.Gasc, serhiy.storchaka, yselivanov, Maxime S |
2016-07-27 00:36:25 | terry.reedy | set | messageid: <1469579785.96.0.0405833241709.issue27546@psf.upfronthosting.co.za> |
2016-07-27 00:36:25 | terry.reedy | link | issue27546 messages |
2016-07-27 00:36:21 | terry.reedy | create | |
|