to implement a cache: is there a thread safe map?

Clark C . Evans cce at clarkevans.com
Sun Aug 12 21:19:30 EDT 2001


Pardon my ignorance here.  I'm rather new to threading
and I have the following situation:

  1.  I have multiple threads.

  2.  I have several constructs ("objects") which
      are very common, costly to construct,
      and should be kept around for a while.

  3.  These objects are static once created, they
      are tuples of strings).  

  4.  The objects are used frequently, and thus
      will be requested all of the time.

  5.  I can't predict what combination of objects
      will be required at compile time.

To be a bit more pragmatic, suppose I have the
following function... 

   def make(args):
       """
           A function that constructs a complicated
           object based on its parameters.
           The object constructed is a constant
           (non-mutable) object, and the parameters
           are also non-mutable.
           
           This is a brain-dead version.
       """
       return args

How could I go about building a "generic", thread-safe
cashe object around the following function.  Thus, I'd 
like...

   cashedmake = CashedFunction(make)
   obj = cashedmake('a')


class CashedFunction:
    def __init__(self,func):
         self.func  = func
         self.cache = {}
    def __call__(self,arg):
         ret = self.cache.get(arg,None)
         if not(res):
             ret = self.func(arg)
             self.cashe[arg] = ret
         return ret

My problem: (Yes, the above probably isn't right)

   1.  How do I make something like the above thread
       safe?  I would add:

           self.lock = threading.Lock()
     
       to the __init__ and then surround
      
           self.lock.acquire()
           ret = self.func(arg)
           self.cashe[arg] = ret
           self.loc.release()

       Is this right?

       a)  It seems that if two threads 
           hit the lock.acquire() at the
           same time, I'll construct the
           object twice... is there a way
           around this?

       b)  It looks like the map could be
           altered mid "get", does the entire
           function need to be locked, or
           can I just lock the mutating portion?

       c)  What other concerns am I missing?

   2.  Dropping items from the cashe.

       I suppose I could make my entries in the
       map (created,value) to store the time 
       it was created, periodically sweeping 
       through the map to clear entries.

       Would a weak reference help here?

       Would it be better to keep another map
       with the last time that a given object
       was accessed?

       
In short... what is the interaction of a map
object and multiple threads.  What do I have
to be concerned about?

Thank you so much,

Clark        









       










More information about the Python-list mailing list