0001 """A generally useful event scheduler class. 0002 0003 Each instance of this class manages its own queue. 0004 No multi-threading is implied; you are supposed to hack that 0005 yourself, or use a single instance per application. 0006 0007 Each instance is parametrized with two functions, one that is 0008 supposed to return the current time, one that is supposed to 0009 implement a delay. You can implement real-time scheduling by 0010 substituting time and sleep from built-in module time, or you can 0011 implement simulated time by writing your own functions. This can 0012 also be used to integrate scheduling with STDWIN events; the delay 0013 function is allowed to modify the queue. Time can be expressed as 0014 integers or floating point numbers, as long as it is consistent. 0015 0016 Events are specified by tuples (time, priority, action, argument). 0017 As in UNIX, lower priority numbers mean higher priority; in this 0018 way the queue can be maintained fully sorted. Execution of the 0019 event means calling the action function, passing it the argument. 0020 Remember that in Python, multiple function arguments can be packed 0021 in a tuple. The action function may be an instance method so it 0022 has another way to reference private data (besides global variables). 0023 Parameterless functions or methods cannot be used, however. 0024 """ 0025 0026 # XXX The timefunc and delayfunc should have been defined as methods 0027 # XXX so you can define new kinds of schedulers using subclassing 0028 # XXX instead of having to define a module or class just to hold 0029 # XXX the global state of your particular time and delay functions. 0030 0031 import bisect 0032 0033 __all__ = ["scheduler"] 0034 0035 class scheduler: 0036 def __init__(self, timefunc, delayfunc): 0037 """Initialize a new instance, passing the time and delay 0038 functions""" 0039 self.queue = [] 0040 self.timefunc = timefunc 0041 self.delayfunc = delayfunc 0042 0043 def enterabs(self, time, priority, action, argument): 0044 """Enter a new event in the queue at an absolute time. 0045 0046 Returns an ID for the event which can be used to remove it, 0047 if necessary. 0048 0049 """ 0050 event = time, priority, action, argument 0051 bisect.insort(self.queue, event) 0052 return event # The ID 0053 0054 def enter(self, delay, priority, action, argument): 0055 """A variant that specifies the time as a relative time. 0056 0057 This is actually the more commonly used interface. 0058 0059 """ 0060 time = self.timefunc() + delay 0061 return self.enterabs(time, priority, action, argument) 0062 0063 def cancel(self, event): 0064 """Remove an event from the queue. 0065 0066 This must be presented the ID as returned by enter(). 0067 If the event is not in the queue, this raises RuntimeError. 0068 0069 """ 0070 self.queue.remove(event) 0071 0072 def empty(self): 0073 """Check whether the queue is empty.""" 0074 return len(self.queue) == 0 0075 0076 def run(self): 0077 """Execute events until the queue is empty. 0078 0079 When there is a positive delay until the first event, the 0080 delay function is called and the event is left in the queue; 0081 otherwise, the event is removed from the queue and executed 0082 (its action function is called, passing it the argument). If 0083 the delay function returns prematurely, it is simply 0084 restarted. 0085 0086 It is legal for both the delay function and the action 0087 function to to modify the queue or to raise an exception; 0088 exceptions are not caught but the scheduler's state remains 0089 well-defined so run() may be called again. 0090 0091 A questionably hack is added to allow other threads to run: 0092 just after an event is executed, a delay of 0 is executed, to 0093 avoid monopolizing the CPU when other threads are also 0094 runnable. 0095 0096 """ 0097 q = self.queue 0098 while q: 0099 time, priority, action, argument = q[0] 0100 now = self.timefunc() 0101 if now < time: 0102 self.delayfunc(time - now) 0103 else: 0104 del q[0] 0105 void = action(*argument) 0106 self.delayfunc(0) # Let other threads run 0107
Generated by PyXR 0.9.4