Welcome, guest | Sign In | My Account | Store | Cart
import types
class method_pseudo_threads(object):
   """
   Implements pseudo threads for class methods.
   """
   _result = None
   
   def __init__(self, caller, instance, *args, **kw):
      self.caller = caller
      self.this_function = self.func(instance, *args, **kw)
      
   def next(self):
      return self.this_function.next()

   def call(self, function, *args, **kwds):
      """
      Check if function is a method of an instance of pseudo_threads.
      If so, call this method via the pseudo_thread mechanism
      """
      special =  hasattr(function, "_parallel")
      if special:
         return (None, function(self.this_function, *args, **kwds))
      else:
         return (function(*args, **kwds), self.this_function)

   def Return(self, value):
      "Return value to the caller"
      return (value, self.caller)
      
   def start(self, thread, *args, **kwds):
      "Start a new pseudo_thread thread, which runs in parallel to the current thread"
      return (None, [self.this_function, thread(None, *args, **kwds)])

   def run(self):
      """
      Calls next for all running threads.
      """
      queue = [self.next()]
      iterations = ticks = 0
      while queue:
         iterations += 1
         newqueue = []
         for result, continuation in queue:
            ticks += 1
            method_pseudo_threads._result = result
            result, continuations = continuation.next()
            if type(continuations) == types.ListType:
               for continuation in continuations:
                  newqueue.append((None, continuation))
            else:
               if continuations:
                     newqueue.append((result, continuations))
         queue = newqueue
      self.iterations, self.ticks = iterations, ticks
      return self._result

def parallel(function):
   """
   Decorator to turn a method into a pseudo_thread.

   The method itself should be written:
   
   def (th, self, *args, **kwds):
      
   Use th.call to call another method which is a pseudo thread.
   Use th.Return to return a value to the caller.
   Use th.start 

   self is the reference to the inclosing instance.
   """
   class p(method_pseudo_threads):
      name = "parallel_class_" + function.func_name
   p.func = function
   def glue(self, caller, *args, **kwds):
      thread = p(caller, self, *args, **kwds)
      yield (None, thread)
   glue._parallel = True
   glue.func_name = "parallel_" + function.func_name
   return glue

class start(method_pseudo_threads):
   def func(self, instance, *args, **kw):
      yield (None, instance)
      yield (None, None)

# Example:

class ackermann(object):
   @parallel
   def acker(th, self, m, n):
      call, Return = th.call, th.Return
      if m == 0:
         yield th.Return(n+1)
      elif m > 0 and n == 0:
         yield call(self.acker, m-1, 1)
         yield Return(th._result)
      elif m > 0 and n > 0:
         yield call(self.acker, m, n-1)
         yield call(self.acker, m-1, th._result)
         yield Return(th._result)
      else:
         assert 0

   @parallel
   def print_ackermann(th, self, m, n):
      yield th.call(self.acker, m, n)
      print "Ackerman(", m, ",", n, ")=", th._result
      yield th.Return(None)
      
   @parallel
   def start(th, self, i, j):
      for i1 in range(i):
         for j1 in range(j):
            yield th.start(self.print_ackermann, i1, j1)
      yield th.Return(None)

def version2():
   ack = ackermann()
   th = ack.start(None, 4, 5)
   start(None, th).run()

if __name__ == '__main__':
   version2()

History