[Stackless-checkins] r53840 - stackless/sandbox/examples/scheduleAlternative.py stackless/sandbox/examples/scheduleNormal.py

richard.tew python-checkins at python.org
Wed Feb 21 19:04:37 CET 2007


Author: richard.tew
Date: Wed Feb 21 19:04:35 2007
New Revision: 53840

Added:
   stackless/sandbox/examples/scheduleAlternative.py
   stackless/sandbox/examples/scheduleNormal.py
Log:
Two examples meant to illustrate the two approaches to scheduling.

Added: stackless/sandbox/examples/scheduleAlternative.py
==============================================================================
--- (empty file)
+++ stackless/sandbox/examples/scheduleAlternative.py	Wed Feb 21 19:04:35 2007
@@ -0,0 +1,114 @@
+#
+# The alternative approach to scheduling.
+#
+# Author: Richard Tew <richard.m.tew at gmail.com>
+#
+# This code was written to serve as an example of Stackless Python usage.
+# Feel free to email me with any questions, comments, or suggestions for
+# improvement.
+#
+# Benefits of this approach:
+#
+# - It lends itself well to embedding, if implemented in C or C++.
+#
+# - It allows more precise control.
+#
+# Limitations of this approach:
+#
+# - The expectation is that the scheduler will be empty because of this
+#   will exit pretty much immediately.  So anything which calls to
+#   'stackless.schedule' rather than using 'BeNice' or 'Sleep' will
+#   break this scheduling model and prevent it from working as
+#   expected.  After all, if there are tasklets in the scheduler it
+#   continues to run and does not exit.
+#
+#   Ideally 'stackless.schedule' should be patched to call BeNice.  Or
+#   calls to it just avoided completely.
+#
+
+import time
+import stackless
+
+yieldChannel = stackless.channel()
+sleepingTasklets = []
+
+# Utility functions for tasklets to call.
+
+def BeNice():
+    """ Signal that the tasklet can be interrupted. """
+    yieldChannel.receive()
+
+def Sleep(secondsToWait):
+    """ Put the current tasklet to sleep for a number of seconds. """
+    channel = stackless.channel()
+    endTime = time.time() + secondsToWait
+    sleepingTasklets.append((endTime, channel))
+    sleepingTasklets.sort()
+    # Block until we get sent an awakening notification.
+    channel.receive()
+
+# Scheduler running related functions.
+
+def CheckSleepingTasklets():
+    """ Awaken all tasklets which are due to be awakened. """
+    while len(sleepingTasklets):
+        endTime = sleepingTasklets[0][0]
+        if endTime > time.time():
+            break
+        channel = sleepingTasklets[0][1]
+        del sleepingTasklets[0]
+        # We have to send something, but it doesn't matter what as it is not used.
+        channel.send(None)
+
+def ScheduleTasklets():
+    # Only schedule as many tasklets as there are waiting when
+    # we start.  This is because some of the tasklets we awaken
+    # may BeNice their way back onto the channel.  Well they
+    # would
+    n = -yieldChannel.balance
+    while n > 0:
+        yieldChannel.send(None)
+        n -= 1
+        
+    CheckSleepingTasklets()
+
+    # Run any tasklets which need to be scheduled.  As long as the BeNice and
+    # Sleep callers do not use schedule they should never be in the scheduler
+    # at this point, but rather back in the yield channel or on a sleep channel.
+    # Loosely guessing, I would say that only newly created tasklets should
+    # ever be in the scheduler.  And nothing should stay in there for that
+    # long before moving out by using Sleep or BeNice.  If something does stay
+    # in there too long then it is not yielding or is keeping the scheduler
+    # running by using 'stackless.schedule' which is not compatible with the
+    # way this method intends the scheduler to be used.
+    
+    interruptedTasklet = stackless.run(1000000)
+    if interruptedTasklet:
+        # Should really print a stacktrace from the tasklet so it can be
+        # rewritten to 'be nice'.  Alternatively the tasklet could be killed
+        # at this point if that suits the application.
+        interruptedTasklet.insert()
+
+exitScheduler = False
+
+def Run():
+    def Test(n):
+        global exitScheduler
+        while n:
+            if n % 2 == 1:
+                print n, "BeNice"
+                BeNice()
+            else:
+                print n, "Sleep"
+                Sleep(1.0)
+            n -= 1
+        exitScheduler = True
+
+    # Do 10 iterations.
+    stackless.tasklet(Test)(10)
+
+    while not exitScheduler:
+        ScheduleTasklets()
+
+if __name__ == '__main__':
+    Run()

Added: stackless/sandbox/examples/scheduleNormal.py
==============================================================================
--- (empty file)
+++ stackless/sandbox/examples/scheduleNormal.py	Wed Feb 21 19:04:35 2007
@@ -0,0 +1,74 @@
+#
+# The normal approach to scheduling.
+#
+# Author: Richard Tew <richard.m.tew at gmail.com>
+#
+# This code was written to serve as an example of Stackless Python usage.
+# Feel free to email me with any questions, comments, or suggestions for
+# improvement.
+#
+# Benefits of this approach:
+#
+# - It is easy to use from the interpreter.
+#
+# Limitations of this approach:
+#
+# - If there are no tasklets that run for the life of the application
+#   or script then the scheduler may exit when things are not complete.
+#   One example of this is when all tasklets which were in the
+#   scheduler and did not complete are waiting on channels.
+#
+
+import time
+import stackless
+
+exitScheduler = False
+
+sleepingTasklets = []
+
+# Utility functions for tasklets to call.
+
+def Sleep(secondsToWait):
+    """ Put the current tasklet to sleep for a number of seconds. """
+    channel = stackless.channel()
+    endTime = time.time() + secondsToWait
+    sleepingTasklets.append((endTime, channel))
+    sleepingTasklets.sort()
+    # Block until we get sent an awakening notification.
+    channel.receive()
+
+# Scheduler running related functions.
+
+def ManageSleepingTasklets():
+    """ Awaken all tasklets which are due to be awakened. """
+    while not exitScheduler:
+        while len(sleepingTasklets):
+            endTime = sleepingTasklets[0][0]
+            if endTime > time.time():
+                break
+            channel = sleepingTasklets[0][1]
+            del sleepingTasklets[0]
+            # It does not matter what we send as it is not used.
+            channel.send(None)
+        stackless.schedule()
+
+
+def Run():
+    def Test(n):
+        global exitScheduler
+        while n:
+            print n, "Sleep"
+            Sleep(1.0)
+            n -= 1
+        exitScheduler = True
+
+    stackless.tasklet(Test)(10)
+    stackless.tasklet(ManageSleepingTasklets)()
+
+    # This will run until there are no scheduled tasklets.  But because we
+    # create one to manage the sleeping tasklets this will mean it will run
+    # indefinitely.
+    stackless.run()
+
+if __name__ == '__main__':
+    Run()

_______________________________________________
Stackless-checkins mailing list
Stackless-checkins at stackless.com
http://www.stackless.com/mailman/listinfo/stackless-checkins



More information about the Stackless-checkins mailing list