yield, curry, mix-in, new.function, global, closure, .... what will work?

Jason tenax.raccoon at gmail.com
Mon Apr 16 11:36:02 EDT 2007


On Apr 16, 7:28 am, ecir.h... at gmail.com wrote:
> On Apr 16, 3:05 am, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
>
> > ecir.h... at gmail.com writes:
>
> > > Please, can you elaborate further, I'm not sure if I understood.
> > > Should I lock global variables i, j during the execution of run()? In
> > > that case I have to apologize, I showed rather simplified version of
> > > the actual problem I have - in fact changer() and run() will be a bit
> > > more complex thus executing a bit longer and perhaps causing a dead-lock.
>
> > Put both variables into one shared object with a lock (see the docs for
> > threading.RLock()).  Acquire the lock before modifying or reading the
> > variables, and release it afterwards.  That is the traditional way.
>
> Thanks for the reply! And at the same time, please bear with me.
>
> If I understand correctly: when one thread acquires the lock, every
> other thread has to wait. If so, this is not exacly what I would like
> to have since the thread might take a bit longer to finish.
>
> The reason why I try so hard to use local variables is that they are
> inherently thread-safe. So I don't even mind to copy changer() every
> time run() is called - run() has it's own local variables i, j, no one
> has to touch them except it's ("local") function changer(). But the
> problem is, I don't know how to propagate run()'s variables into
> changer() without declarating them as changer()'s arguments (it would
> be ok to append the declaration during run-time, though, if I only
> knew how).

In Python, names are bound to objects.  The parameter names passed to
a function *are not inherently thread safe*!  Python parameters are
not passed-by-value.  To show you what I mean:

>>> spam = ["delicious"]
>>> def test(meal):
...  global spam
...  if spam is meal:
...    print "Spam is the same object as meal"
...
>>> test(spam)
Spam is the same object as meal

(While the "global spam" statement is optional in this case, I wanted
to make it painfully obvious where the "spam" name in function test is
coming from.)

It is thread-safe to rebind the name "meal" in the function test (ie,
meal = "Green eggs").   It is not thread-safe to mutate or modify the
object that meal is bound to.  In the example given above, appending
data to the list, removing data, changing elements, and other
operations will cause potential race conditions across multiple
threads.

Follow Paul's advice and get acquainted with the issues of concurrent
and threaded programming.  Judicious locking will help avoid most race
conditions.  If you don't want to keep other threads waiting, make a
copy of your data then release the data lock.

Depending on the data, you can usually have multiple threads "reading"
the data, as long as no other threads write to the data while there
are any readers.  A writer can be allowed to change the data, but only
if there are no readers and no other writers.  (This is commonly known
as a read/write lock.)  I didn't see a read/write lock in the Python
documentation with some casual browsing, but one can be implemented
from the existing thread locking mechanisms.

Your description of what you want to do is rather vague, so I can't
get too specific.  You've described how you want to do things, but I
don't know what you're trying to accomplish.  Where possible, simplify
your design.

    --Jason




More information about the Python-list mailing list