Synchronization methodology

Discussion in 'Python' started by Chris Ashurst, Jan 3, 2007.

  1. Hi, I'm coming in from a despised Java background, and I'm having some
    trouble wrapping my head around sharing an object between multiple
    instances of a single class (in simpler terms, I would say imagine a
    simple chat server that has to share a list of connected users to each
    instance of a connected user).

    Usually, I would have a synchronized list instantiated inside each
    instance of a client class, which would do the trick, but since there's
    no synchronization in Python, I'm stuck staring at little tests
    involving a standalone non-threaded class instance that holds the list
    of users, and each connected user being passed this instance to be
    "synchronized".

    Now, whilst this *works*, it just doesn't feel right, and I would
    appreciate it if anyone has any more Pythonic expressions of this paradigm.

    Note that I have looked at Twisted (and I use it for other stuff), but
    I'm wanting to do things at a lower level (because I'm masochistic), and
    I feel like all the fun has been sucked out of programming by basically
    telling Twisted what I want and have it do it for me invisibly.

    Thanks!


    ~Chris
     
    Chris Ashurst, Jan 3, 2007
    #1
    1. Advertising

  2. In <>, Chris Ashurst
    wrote:

    > Hi, I'm coming in from a despised Java background, and I'm having some
    > trouble wrapping my head around sharing an object between multiple
    > instances of a single class (in simpler terms, I would say imagine a
    > simple chat server that has to share a list of connected users to each
    > instance of a connected user).
    >
    > Usually, I would have a synchronized list instantiated inside each
    > instance of a client class, which would do the trick, but since there's
    > no synchronization in Python, I'm stuck staring at little tests
    > involving a standalone non-threaded class instance that holds the list
    > of users, and each connected user being passed this instance to be
    > "synchronized".


    There's no ``synchronized`` keyword, but of course you can synchronize
    methods. You have to attach an `threading.RLock` to the objects you want
    to synchronize on and use its `aquire()` and `release()` methods in places
    where you used ``synchronized (someObject) { ... }`` in Java.

    synchronized foo() { /* code */ }

    is the same as

    foo() {
    synchronized (this) { /* code */ }
    }

    in Java. And that's basically:

    def foo(self):
    self.lock.aquire()
    # code
    self.lock.release()

    You may want to make sure the lock will be released in case of an
    exception:

    def foo(self):
    self.lock.aquire()
    try:
    pass # code
    finally:
    self.lock.release()

    Ciao,
    Marc 'BlackJack' Rintsch
     
    Marc 'BlackJack' Rintsch, Jan 3, 2007
    #2
    1. Advertising

  3. Chris Ashurst

    Guest

    Chris Ashurst wrote:
    > Hi, I'm coming in from a despised Java background


    Consider strongly the fact that Python supports multiple process
    solutions well, so you're not stuck having to use multithreaded
    solutions in every circumstance (but can still use them when necessary).
     
    , Jan 3, 2007
    #3
  4. Chris Ashurst

    Paul Rubin Guest

    Chris Ashurst <> writes:
    > Hi, I'm coming in from a despised Java background, and I'm having some
    > trouble wrapping my head around sharing an object between multiple
    > instances of a single class (in simpler terms, I would say imagine a
    > simple chat server that has to share a list of connected users to each
    > instance of a connected user).


    If you're doing this with threads, one common Pythonic style is
    generally to have the threads communicate through queues (see docs for
    the Queue module). This is sort of a cheap version of the CSP
    (communicating sequential processes) approach. You might have a
    service thread that takes care of those shared objects, reading
    requests from a queue (untested):

    # All client threads write their requests to this queue, and
    # the service loop reads from it
    service_queue = Queue()

    # make one of these in each client thread
    class Request(Queue.Queue):
    def __call__(self, reply_queue, func, *args, **kwargs):
    service_queue.put((self, func, args, kwargs))
    return self.get()

    def service_loop():
    while True:
    client, func, args, kwargs = service_queue.get()
    client.put (func(*args, **kwargs))

    Threading.Thread(target=service_loop).start()

    Then in your connected user thread you could say:

    # set up a reply queue for this user's thread
    request = Request()
    ...

    # add the user to the connected user list, with timestamp and remote IP
    status = request(user_list.append, self, time(), remote_ip=whatever)

    The last line would drop a request on the service queue to perform the
    function call

    user_list.append(time(), remote_ip=whatever)

    The service queue thread would retrieve the request, call the
    function, and pass the result back through the reply queue. The idea
    is you'd handle all operations on user_list in the service thread, so
    access is completely serialized using the queues. You can see that
    you can easily construct any function call that then gets executed in
    the other thread, without having to use a bunch of boilerplate at each
    request. You have to be a bit careful to not use long-running
    requests that could block other threads from getting their requests
    serviced. Use additional threads if you need such requests.

    You sometimes end up creating more threads than necessary this way but
    you tend to not have many synchronization problems if you stick with
    this style.
     
    Paul Rubin, Jan 3, 2007
    #4
  5. Chris Ashurst

    Paul Rubin Guest

    Paul Rubin <http://> writes:
    > # add the user to the connected user list, with timestamp and remote IP
    > status = request(user_list.append, self, time(), remote_ip=whatever)


    Editing error, ignore the "self," arg up there. Of course there may be
    other mistakes too, I didn't test any of that code ;-)
     
    Paul Rubin, Jan 3, 2007
    #5
  6. Chris Ashurst

    Duncan Booth Guest

    Marc 'BlackJack' Rintsch <> wrote:

    > You may want to make sure the lock will be released in case of an
    > exception:
    >
    > def foo(self):
    > self.lock.aquire()
    > try:
    > pass # code
    > finally:
    > self.lock.release()
    >


    In Python 2.5 this can also be written more succintly using the with
    statement so foo becomes:

    from __future__ import with_statement
    ....

    def foo(self):
    with self.lock:
    pass # insert your code here


    or write a decorator.
     
    Duncan Booth, Jan 3, 2007
    #6
  7. Hi Chris,

    Have you looked at the mutex module?

    Jeremy
     
    Jeremy Dillworth, Jan 3, 2007
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. imavroid
    Replies:
    0
    Views:
    843
    imavroid
    Mar 12, 2006
  2. Replies:
    3
    Views:
    442
    Clint Hill
    Jul 25, 2005
  3. Imran Aziz
    Replies:
    2
    Views:
    1,213
    Imran Aziz
    Aug 5, 2005
  4. Ted Holden

    CORBA or some other methodology?

    Ted Holden, Nov 18, 2004, in forum: Java
    Replies:
    12
    Views:
    599
    ted holden
    Nov 22, 2004
  5. arieljake
    Replies:
    3
    Views:
    343
    arieljake
    Feb 9, 2005
Loading...

Share This Page