This simple generator function is used to call a function X times per second.
1 2 3 4 5 6 7 8 9 10 11 12 13
def timed_call(callback, calls_per_second, *args, **kw): """ Create an iterator which will call a function a set number of times per second. """ time_time = time.time start = time_time() period = 1.0 / calls_per_second while True: if (time_time() - start) > period: start += period callback(*args, **kw) yield None
This iterator is useful for many things. I use it to control timed updates to objects in my games. It is especially useful for animating objects at a constant frame rate across systems with different processor speeds and video refresh rates.
You can call the iterator as often as possible in the main loop, and be assured that it will only run the callback function X times per second.
timing error. This recipe will call the function at most the number of times per second. You don't want to reset the start time to NOW after the call but to increment it by the period. If the time between calls should be 5 seconds and the function call takes 1 second you want to wait 4 seconds before calling it again, not 5.
Ah yes, agreed. The callback functions I'm using are so small, I did not detect any timing errors. Updating recipe...
Alternate Strategy. In the context of game updates, the recipe's strategy bogs down when there are many recurring events. The caller is burdened by having to make frequent, unnecessary calls to event.next() in order to check whether each recurring event is ready to run. Not knowing which event is to occur next, the caller has to try calling each until one fires off -- essentially, this is a linear search. All of these calls consume CPU time even when events are scheduled for infrequent update intervals.
Instead of a linear search, the order of execution can be kept in a priority queue so that only the next scheduled event is called. Another improvement is use time.sleep() between events so as to not eat-up CPU time that could be used by other threads. The API can be improved by creating a task manager responsible for making the calls (instead of burdening the caller with the responsibility for tracking each event separately). Since these three improvements are already encapsulated in the sched module, an implementation is straight-forward:
Note, the order of arguments was changed from the original. For better readability, the callback function needs to be listed adjacent to its arguments.
Also note, Windows users should substitute time.clock for time.time.