[Python-checkins] python/dist/src/Lib sched.py,1.14,1.15

rhettinger at users.sourceforge.net rhettinger at users.sourceforge.net
Fri Dec 17 14:52:23 CET 2004


Update of /cvsroot/python/python/dist/src/Lib
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6436

Modified Files:
	sched.py 
Log Message:
Refactor:
* Improve algorithm -- no more O(n) steps except sched.cancel().
* Improve thread safety of sched.run() and sched.empty()
  (other threads could alter the queue between the time the queue was
   first checked and when the lead event was deleted).
* Localize variable access in sched.run() to minimize overhead.



Index: sched.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/sched.py,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- sched.py	27 Feb 2003 20:14:41 -0000	1.14
+++ sched.py	17 Dec 2004 13:52:20 -0000	1.15
@@ -15,7 +15,7 @@
 
 Events are specified by tuples (time, priority, action, argument).
 As in UNIX, lower priority numbers mean higher priority; in this
-way the queue can be maintained fully sorted.  Execution of the
+way the queue can be maintained as a priority queue.  Execution of the
 event means calling the action function, passing it the argument.
 Remember that in Python, multiple function arguments can be packed
 in a tuple.   The action function may be an instance method so it
@@ -28,7 +28,7 @@
 # XXX instead of having to define a module or class just to hold
 # XXX the global state of your particular time and delay functions.
 
-import bisect
+import heapq
 
 __all__ = ["scheduler"]
 
@@ -48,7 +48,7 @@
 
         """
         event = time, priority, action, argument
-        bisect.insort(self.queue, event)
+        heapq.heappush(self.queue, event)
         return event # The ID
 
     def enter(self, delay, priority, action, argument):
@@ -68,10 +68,11 @@
 
         """
         self.queue.remove(event)
+        heapq.heapify(self.queue)
 
     def empty(self):
         """Check whether the queue is empty."""
-        return len(self.queue) == 0
+        return not not self.queue
 
     def run(self):
         """Execute events until the queue is empty.
@@ -94,13 +95,23 @@
         runnable.
 
         """
+        # localize variable access to minimize overhead
+        # and to improve thread safety
         q = self.queue
+        delayfunc = self.delayfunc
+        timefunc = self.timefunc
+        pop = heapq.heappop
         while q:
-            time, priority, action, argument = q[0]
-            now = self.timefunc()
+            time, priority, action, argument = checked_event = q[0]
+            now = timefunc()
             if now < time:
-                self.delayfunc(time - now)
+                delayfunc(time - now)
             else:
-                del q[0]
-                void = action(*argument)
-                self.delayfunc(0)   # Let other threads run
+                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:
+                    void = action(*argument)
+                    delayfunc(0)   # Let other threads run
+                else:
+                    heapq.heappush(event)



More information about the Python-checkins mailing list