Synchronization mixin in Python anyone?

Gustavo Cordova gcordova at hebmex.com
Mon May 6 09:37:29 EDT 2002


> Gustavo Cordova <gcordova at hebmex.com> wrote in 
> news:mailman.1020461587.9261.python-list at python.org:
> > Hmmm... interesting problem. I've been playing with a function
> > synchronization class lately, just toying with the idea. I don't
> > know if anybody wants it, but here's the basic skeleton:
> > 
> > ### SynchronizedCall
> > import thread
> > 
> > class SynchronizedCall:
> >    def __init__(self, function, *args, **kw):
> >       self._lock = thread.Lock()
> >       self._args = args
> >       self._kw = kw
> >       self._function = function
> > 
> >   def __call__(self, *args, **kw):
> >       self._lock.acquire()
> >       try:
> >          args = self._args + args
> >          kw.update(self._kw)
> >          result = self._function(*args, **kw)
> > 
> >       ## In case of an exception, release lock first.
> >       except:
> >          self._lock.release()
> >          raise
> > 
> >       self._lock.release()
> >       return result
> > 
> > ## THE END
> 
> the "except" is wrong placed here - that's what "try: 
> finally:" is for:
> 
>        try:
>           args = self._args + args
>           kw.update(self._kw)
>           return = self._function(*args, **kw)
>        finally:       
>           self._lock.release()
> 

But what about any exception that's raised?

Does the finally: clause re-raise the exception so that
it can be caught upstream?

>
> > Really quite simple.
> 
> well, you're mixing locking and currying in one wrapper.
> i would prefer to have them separately.
>  

Well, yeah; but the currying here comes practically for free,
and since you don't *have* to pass any default arguments,
you can not-curry if you don't like curry. :-)

>
> > The thing that discouraged me from trying to do this with
> > instance methods, is that it becomes a bit complicated if
> > someone takes a reference to a method, like I do commonly:
> > 
> > ## Example
> > 
> > rex = sre.compile(r"really big and complicated", sre.S|sre.I)
> > 
> > find_everything = rex.findall
> > 
> > while ... :
> >    ...
> >    things = find_everything(string)
> >    ...
> > 
> > ## End example
> > 
> > So, how would I protect calls to rex.findall() when they're
> > done through find_everything() ?
> 
> by replacing rex.findall with the wrapped method.
> something like that:
>
> rex.__class__.findall = SynchronizedCall(rex.__class__.findall)
>
> (note that this has side effects on all instaces of the 
> "Regular Expression Object" and therefore should be considered evil)
> 

Yes; it'll block for all instances of "Regular Expression Object",
which is what makes this so complicated. :-)

> 
> with user defined classes this at least looks easier:
> 
> class A:
>     	def f():
>     	    	print "hello"
>     	f = SynchronizedCall(f)
> 
> the problem here, like above, is that it has an effect on all 
> instaces of A, because there is only _one_ lock for all instances.
> not realy what you want...
> 
> the SynchronizedCall wrapper might be too simple for OO. i 
> think it makes more sense when one method can lock out another
> on the same instance, like "synchronized" in Java (e.g. get
> and set methods for an attribute can not be called at the same
> time). maybe it is that what the OP wanted with his mix-in.
> 
> chris
> 

Yes, I was thinking of something like that with the regex example,
a way to block between the time a thread enters *any* method of an
instance, until it exits the method. And that's where it gets
complicated.

Maybe with some little hacking of the interpreter, we could make
a "synchronized" function, like "property()".

Who knows :-)

-gustavo





More information about the Python-list mailing list