diff --git a/Lib/sched.py b/Lib/sched.py --- a/Lib/sched.py +++ b/Lib/sched.py @@ -34,6 +34,9 @@ __all__ = ["scheduler"] class Event(namedtuple('Event', 'time, priority, action, argument')): + def __init__(self, *args, **kwargs): + super(Event, self).__init__(*args, **kwargs) + self._cancelled = False def __eq__(s, o): return (s.time, s.priority) == (o.time, o.priority) def __ne__(s, o): return (s.time, s.priority) != (o.time, o.priority) def __lt__(s, o): return (s.time, s.priority) < (o.time, o.priority) @@ -42,10 +45,13 @@ def __ge__(s, o): return (s.time, s.priority) >= (o.time, o.priority) class scheduler: + cancellations_threshold = 1024 + def __init__(self, timefunc, delayfunc): """Initialize a new instance, passing the time and delay functions""" self._queue = [] + self._cancellations = 0 self.timefunc = timefunc self.delayfunc = delayfunc @@ -76,8 +82,8 @@ If the event is not in the queue, this raises ValueError. """ - self._queue.remove(event) - heapq.heapify(self._queue) + self._cancellations += 1 + event._cancelled = True def empty(self): """Check whether the queue is empty.""" @@ -114,14 +120,21 @@ time, priority, action, argument = checked_event = q[0] now = timefunc() if now < time: + if self._cancellations > self.cancellations_threshold: + self._cancellations = 0 + self._queue = [x for x in self._queue if not x._cancelled] + heapq.heapify(self._queue) delayfunc(time - now) else: event = pop(q) # Verify that the event was not removed or altered # by another thread after we last looked at q[0]. if event is checked_event: - action(*argument) - delayfunc(0) # Let other threads run + if event._cancelled: + self._cancellations -= 1 + else: + action(*argument) + delayfunc(0) # Let other threads run else: heapq.heappush(q, event)