Skip to content Skip to sidebar Skip to footer

Synchronize Access To Python Object

I am looking for a general and simple way to synchronize the methods of a python class that does not use asynchronous calls by itself. Some possibilities come to my mind: First, th

Solution 1:

If you really need to, you can use the black magic of python metaclasses to dynamically add a decorator to each method of the class at class creation time. The following is a quick example of how you might do this. It creates a generic synchronizer metaclass, which you then subclass to create synchronizers for each specific class. Finally you subclass the original class that you want to synchronize and apply the synchronizer metaclass to it. Note I'm using python 3 metaclass syntax.

from threading import RLock

## Generic synchronizer#classSynchroMeta(type):

    def__init__(cls, name, bases, dct):
        super(SynchroMeta, cls).__init__(name, bases, dct)
        dct['__lock__'] = RLock()

        defsync_decorator(f):
            definner(*args, **kwargs):
                with dct['__lock__']:
                    print("Synchronized call")
                    return f(*args, **kwargs)
            return inner

        for b in bases:
            if b.__name__ == cls.sync_object_name:
                for name, obj in b.__dict__.items():
                    # Synchronize any callables, but avoid special functionsifhasattr(obj, '__call__') andnot name.startswith('__'):
                        print("Decorating: ", name)
                        setattr(b, name, sync_decorator(obj))

## Class you want to synchronize#classMyClass:
    def__init__(self, v):
        self.value = v

    defprint_value(self):
        print("MyClass.value: ", self.value)

## Specific synchronizer for "MyClass" type#classMyClassSynchro(SynchroMeta):
    sync_object_name = "MyClass"## Wrapper that uses the specific synchronizer metaclass#classMyClassWrapper(MyClass, metaclass=MyClassSynchro):
    passif __name__ == "__main__":
    w = MyClassWrapper('hello')
    w.print_value()

Solution 2:

I went with the SynchronizeProxy, and it seems to work so far. Since this solution comes closest to what I need, I will select my answer as a solution. If I experience any problems, I will update this answer.

#!/usr/bin/env pythonimport types
from pprint import pformat
from threading import RLock

classSynchronizeMethodWrapper:
    """
    Wrapper object for a method to be called.
    """def__init__( self, obj, func, name, rlock ):
        self.obj, self.func, self.name = obj, func, name
        self.rlock = rlock
        assert obj isnotNoneassert func isnotNoneassert name isnotNonedef__call__( self, *args, **kwds ):
        """
        This method gets called before a method is called to sync access to the core object.
        """with self.rlock:
            rval = self.func(*args, **kwds)
            return rval


classSynchronizeProxy(object):
    """
    Proxy object that synchronizes access to a core object methods and attributes that don't start with _.
    """def__init__( self, core ):
        self._obj = core
        self.rlock = RLock()

    def__getattribute__( self, name ):
        """
        Return a proxy wrapper object if this is a method call.
        """if name.startswith('_'):
            returnobject.__getattribute__(self, name)
        else:
            att = getattr(self._obj, name)
            iftype(att) is types.MethodType:
                return SynchronizeMethodWrapper(self, att, name, object.__getattribute__(self, "rlock"))
            else:
                return att

    def__setitem__( self, key, value ):
        """
        Delegate [] syntax.
        """
        name = '__setitem__'with self.rlock:
            att = getattr(self._obj, name)
            pmeth = SynchronizeMethodWrapper(self, att, name, self.rlock)
            pmeth(key, value)

Solution 3:

You could use a queue to proxy the calls to that class:

http://pymotw.com/2/Queue/

Update:

Actually now that I think about it a queue might not be the best solution because you'd probably have to adapt the class at least a little bit to work with the queue. If you wan't to use locks you could take a look at threading.Lock() here: http://docs.python.org/2/library/threading.html

Post a Comment for "Synchronize Access To Python Object"