Welcome, guest | Sign In | My Account | Store | Cart

Describes a simple example of the potential for shared Singleton or Borg object methods to be proxy'd by an object that SyncManger can present to requesting subprocesses.

Python, 122 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env python
import inspect
import multiprocessing
from multiprocessing.managers import SyncManager
import new, sys, types, time, datetime, random

#
#
#
class Commander(object):
   '''
      object to handle all requests
      from delegates. purpose generally to be
      borg or singleton of an object that can
      not be easily shared between different processes.
      Just an Example....
   '''
   def __init__(self, prefix='with_',**kwds):
      self._createTime = datetime.datetime.now()
      self._prefix = prefix
      self.id = random.Random()
      for k,v in kwds.items():
         setattr(self, k, v)
   #
   @property
   def Prefix(self):
      return self._prefix
   #
   @property
   def Commands(self):
      # want a dict comprehension that returns 
      # k,v of name of method, method for
      # method names that start with Prefix
      # but
      # dict comprehensions require another
      # dicussion entirely
      return self.__dict__.items()
   #
   def with_exposed(self, *args, **kwds):
      '''
         method exposed to SyncManager and 'the world'
         will print to std obj ids
      '''
      stack = inspect.stack()[0] # trying to make this file readable
      print '\n***\nCommander_%s.\nwith_exposed(%s, %s)called\nbound to self id %s\nand id %s\n***'%(
         stack, str(args), str(kwds), str(self), str(self.id)
         )
#
#
#
class _DelegatedMethod(object):
   '''
      idea of this class was lifted from Pyro.core
      i might put a async process here in __call__
      but didn't want to mess with callbks for an example
   '''
   def __init__(self, f, name):
      self.__f = f
      self.__name = name
   def __call__(self, *args, **kwds):
      return self.__f(*args, **kwds)
#
#
#
class CommanderDelegate(object):
   '''
      dynamic delegate for a Commander class
      should make sure its type Commander.
      As long as its a Commander, a sort of Mixin
      would be helpful, following the API. 'with_'
      or whatever was appropriate
   '''
   #
   def __init__(self, commanderClz, *args, **kwds):
      self._dispatchMap = {}
      self._commander = commanderClz(*args, **kwds)
      for m in inspect.getmembers(self._commander):
         if inspect.ismethod(m[1]) and m[0].startswith(self._commander.Prefix):
            self._dispatchMap[m[0]] = m[1]
   #
   def __getattribute__(self, name):
      # the important bits...
      d = object.__getattribute__(self, '_dispatchMap')
      if d.has_key(name):
         return _DelegatedMethod(d[name], name)
      return object.__getattribute__(self, name)
#
#
#
class SharedProctor(SyncManager):
   def __init__(self):
      SyncManager.__init__(self)
      self.register('CommanderProctor', 
            callable=CommanderDelegate, 
            exposed=('with_exposed',))
#
#
#
class MyProcess(multiprocessing.Process):
   #
   def __init__(self, dp=None, dpLock=None):
      multiprocessing.Process.__init__(self)
      self.dp = dp
      self.dpLock = dpLock
   def run(self):
      self.__say()
   def __say(self):
      with self.dpLock:
         s = self.dp.with_exposed()
#     
if __name__ == '__main__':
   
   sp = SharedProctor()
   sp.start()
   cp = sp.CommanderProctor(Commander)
   cpLock = sp.Lock()
   for i in xrange(0,100):
      m = MyProcess(dp=cp, dpLock=cpLock)
      m.start()
      time.sleep(.01)
   
   m.join()
   

If an object created by a factory method in the multiprocessing module is a Singleton, Borg, or not serializable, this pattern can help. Generates a decoupled proxy using the classic dispatch pattern. Giving access to one object or access to one state though a proxy of named methods, presenting to the requesting subprocess.

Useful for system, web, or db synchronised access.