[Python-Dev] A few lessons from the tempfile.py rewrite
Tim Peters
tim.one@comcast.net
Sat, 17 Aug 2002 11:12:13 -0400
[Zack Weinberg]
> ...
> 2) pthread_once equivalent.
>
> pthread_once is a handy function in the C pthreads library which
> can be used to guarantee that some data object is initialized exactly
> once, and no thread sees it in a partially initialized state.
I don't know that it comes up enough in Python to bother doing something
about it -- as Guido said, there's an import lock under the covers that
ensures only one thread executes module init code (== all "top level" code
in a module). So modules that need one-shot initialization can simply do it
at module level. tempfile has traditionally gone overboard in avoiding use
of this feature, though.
A more Pythonic approach may be gotten via emulating pthread_once more
closely, forgetting the "data object" business in favor of executing
arbitrary functions "just once". Like so, maybe:
def do_once(func, lock=threading.RLock(), done={}):
if func not in done:
lock.acquire()
try:
if func not in done:
func()
done[func] = True
finally:
lock.release()
"done" is a set of function objects that have already been run, represented
by a dict mapping function objects to bools (although the dict values make
no difference, only key presence matters). Default arguments are abused
here to give do_once persistent bindings to objects without polluting the
global namespace. A more purist alternative is
def do_once(func):
if func not in do_once.done:
do_once.lock.acquire()
try:
if func not in do_once.done:
func()
do_once.done[func] = True
finally:
do_once.lock.release()
do_once.lock = threading.RLock()
do_once.done = {}
This is "more Pythonic", chiefly in not trying to play presumptive games
with namespaces. If some module M wants to set its own attr goob, fine, M
can do
def setgoob():
global goob
goob = 42
do_once(setgoob)
and regardless of which module do_once came from. Now what setgoob does is
utterly obvious, and do_once() doesn't make helpful assumptions that get in
the way <wink>.