"Synchronized" in python

Bruce Eckel Bruce at EckelObjects.com
Sun Dec 9 15:03:46 EST 2001


Peter:
I think I've gotten all the kinks out of the design except two.
I've attached the current incarnation of the files, including
Synchronization.py and TestSynchronization.py. The two kinks are:

1) I can't figure out how to prevent multiple synchronization of a
method, as in the example of 'm' in the test code. I tried
attaching an attribute to the function 'f' that is returned by
synchronized() and then hunting for it in synchronize(), but the
attribute doesn't seem to hang around.

2) is there any clever way to effect a synchronized *clause* inside
a method, rather than synchronizing the whole method?


*********** REPLY SEPARATOR  ***********

On 12/6/01 at 10:26 AM Peter Norvig wrote:

>Or how about this:
>
>def Synchronize(klass, names=None):
>  """Synchronize methods in the given class.  
>  Only synchronize the methods whose names are given, or all
methods
>  if names=None (the default)."""
>  if type(names) = type(''): names = names.split()
>  for (name, val) in klass.__dict__.items():
>    if callable(val) and (names == None or name in names):
>      klass.__dict__[name] = synchronize(val)
>
># use like this:
>Synchronize(MyClass)
>Synchronize(SomeClass, "method1 method2 method3")
>
>
>Bruce Eckel wrote:
>> 
>> Interesting.
>> It turns out that threading.RLock is the right one to use, as
>> thread.allocate_lock() doesn't allow synchronized methods to
call
>> each other, like you can in Java.
>> 
>> I couldn't tell from this, is it possible to syncronize on a
>> method-by-method basis?
>> 
>> *********** REPLY SEPARATOR  ***********
>> 
>> On 12/6/01 at 9:23 AM Peter Norvig wrote:
>> 
>> >How about this, mostly copied from Guido's article, with minor
>> changes:
>> >
>> >import types, thread
>> >
>> >class SynchronizedMetaclass:
>> >    def __init__(self, name, bases, namespace):
>> >        """Create a new class."""
>> >        self.__name__ = name
>> >        self.__bases__ = bases
>> >        self.__namespace__ = namespace
>> >    def __call__(self):
>> >        """Create a new instance."""
>> >        return Instance(self)
>> >
>> >class Instance:
>> >    def __init__(self, klass):
>> >        self.mutex = thread.allocate_lock()
>> >        self.__klass__ = klass
>> >    def __getattr__(self, name):
>> >        try:
>> >            value = self.__klass__.__namespace__[name]
>> >        except KeyError:
>> >            raise AttributeError, name
>> >        if type(value) is not types.FunctionType:
>> >            return value
>> >        return BoundMethod(value, self)
>> >
>> >class BoundMethod:
>> >    def __init__(self, function, instance):
>> >        self.function = function
>> >        self.instance = instance
>> >    def __call__(self, *args):
>> >      self.instance.mutex.acquire(); print 'acquired' ##
debugging
>> >      result = None
>> >      try:
>> >        result = apply(self.function, (self.instance,) + args)
>> >      finally:
>> >        self.instance.mutex.release(); print 'released'
>> ##debugging
>> >      return result
>> >
>> >
>> >Synchronized = SynchronizedMetaclass('Synchronized', (), {})
>> >
>> >class My(Synchronized):
>> >    def method1(self, a):
>> >        self.a = a
>> >    def method2(self):
>> >        return self.a
>> >
>> >m = My()
>> >
>> >print 'm.method1(42)', m.method1(42)
>> >print 'm.method2()', m.method2()
>> >
>> >Tim Peters wrote:
>> >>
>> >> Bruce, I'm afraid that's not a good emulation.  Much better
than
>> >>
>> >>     def xxx(...):
>> >>         self.mutex.acquire()
>> >>         yadda
>> >>         self.mutex.release()
>> >>
>> >> is
>> >>
>> >>     def xxx(...):
>> >>         self.mutex.acquire()
>> >>         try:
>> >>             yadda
>> >>         finally:
>> >>             self.mutex.release()
>> >>
>> >> which is, alas, even more noxious by hand.  Key side
question:
>> are you
>> >sure
>> >> you want mutex semantics here?  A more popular alternative is
to
>> use a
>> >> threading.RLock (a reentrant lock, so that Observable's
>> synchronized
>> >methods
>> >> can call each other freely without deadlocking (or even more
>> manual
>> >pain)).
>> >>
>> >> There's no easy relief.  I can't make time to go into the
>> details now, so
>> >> ask on comp.lang.python if you're really curious:
metaclasses
>> can be
>> >used
>> >> to automate this.  This should be much simpler in 2.2 than in
>> previous
>> >> releases, as 2.2 introduces some seriously usable
Python-level
>> metaclass
>> >> machinery.  The flavor of what you need before 2.2 can be
found
>> in the
>> >> Demo/metaclasses subdirectory of your Python tree; in
>> particular,
>> >Synch.py
>> >> there is an example of a metaclass for adding synchronized
>> methods.
>> >>
>> >> Unfortunately, nobody has had time to update the examples in
>> that
>> >directory
>> >> for 2.2.  The pre-2.2 metaclass hook is notoriously difficult
to
>> >understand.
>> >> Guido's old essay on the topic
>> >>
>> >>     http://www.python.org/doc/essays/metaclasses/
>> >>
>> >> is still quoted often, but more in frustration than
admiration
>> <wink>.
>> >>
>> >> technically-accurate-yet-almost-entirely-unrevealing-ly y'rs
-
>> tim
>> >>
>> >> > -----Original Message-----
>> >> > From: Bruce Eckel [mailto:Bruce at EckelObjects.com]
>> >> > Sent: Wednesday, December 05, 2001 9:19 PM
>> >> > To: Peter Norvig; tim.one at home.com
>> >> > Subject: "Synchronized" in python
>> >> >
>> >> >
>> >> > Do you know of a clever way to emulate Java's
"synchronized"
>> in
>> >> > Python? Right now I have:
>> >> >
>> >> > import thread
>> >> >
>> >> > class Observable:
>> >> >   def __init__(self) {
>> >> >     self.obs = []
>> >> >     self.changed = 0;
>> >> >     self.mutex = thread.allocate_lock()
>> >> >   def addObserver(self, observer):
>> >> >     self.mutex.acquire()
>> >> >     if observer not in obs:
>> >> >         obs.append(observer)
>> >> >     self.mutex.release()
>> >> >   def deleteObserver(self, observer):
>> >> >     self.mutex.acquire()
>> >> >     del obs[observer]
>> >> >     self.mutex.release()
>> >> >
>> >> > etc.
>> >> >
>> >> > I'm wondering if there's some better way than reproducing
all
>> those
>> >> > "self.mutex.acquire()" and "self.mutex.release()"
statements
>> for
>> >> > each synchronized method.
>> >> >
>> >> >
>> >> > Most current information can be found at:
>> >> > http://www.mindview.net/Etc/notes.html
>> >> > ===================
>> >> > Bruce Eckel    http://www.BruceEckel.com
>> >> > Contains free electronic books: "Thinking in Java 2e" &
>> "Thinking
>> >> > in C++ 2e"
>> >> > Please subscribe to my free newsletter -- just send any
email
>> to:
>> >> > join-eckel-oo-programming at earth.lyris.net
>> >> > My schedule can be found at:
>> >> > http://www.mindview.net/Calendar
>> >> > ===================
>> >
>> >--
>>
>___________________________________________________________________

>> __
>> >Peter Norvig, Director of Machine Learning, Google,
>> http://google.com
>> >pnorvig at google.com,  Voice:650-330-0100 x1248,
Fax:650-618-1499
>> 
>> Most current information can be found at:
>> http://www.mindview.net/Etc/notes.html
>> ===================
>> Bruce Eckel    http://www.BruceEckel.com
>> Contains free electronic books: "Thinking in Java 2e" &
"Thinking
>> in C++ 2e"
>> Please subscribe to my free newsletter -- just send any email
to:
>> join-eckel-oo-programming at earth.lyris.net
>> My schedule can be found at:
>> http://www.mindview.net/Calendar
>> ===================
>
>-- 
>___________________________________________________________________
__
>Peter Norvig, Director of Machine Learning, Google,
http://google.com
>pnorvig at google.com,  Voice:650-330-0100 x1248,  Fax:650-618-1499



Most current information can be found at:
http://www.mindview.net/Etc/notes.html
===================
Bruce Eckel    http://www.BruceEckel.com
Contains free electronic books: "Thinking in Java 2e" & "Thinking
in C++ 2e"
Please subscribe to my free newsletter -- just send any email to:
join-eckel-oo-programming at earth.lyris.net
My schedule can be found at:
http://www.mindview.net/Calendar
===================

-------------- next part --------------
A non-text attachment was scrubbed...
Name: Synchronization.zip
Type: application/x-zip-compressed
Size: 1222 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/python-list/attachments/20011209/5052dfe7/attachment.bin>


More information about the Python-list mailing list