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