Allow cachedproperty to avoid locking

Under some cirumstances it is ok to recompute
a value when raced to by multiple threads, for these
cases allow the cachedproperty to avoid needing and
using a lock.

Change-Id: Icb71cb5ea280185cfb120671be900435dabcd50b
This commit is contained in:
Joshua Harlow
2016-02-08 23:16:58 -08:00
parent 61efc31e96
commit b033fa6722

View File

@@ -350,8 +350,11 @@ class cachedproperty(object):
cached property would be stored under '_get_thing' in the self object cached property would be stored under '_get_thing' in the self object
after the first call to 'get_thing' occurs. after the first call to 'get_thing' occurs.
""" """
def __init__(self, fget): def __init__(self, fget=None, require_lock=True):
self._lock = threading.RLock() if require_lock:
self._lock = threading.RLock()
else:
self._lock = None
# If a name is provided (as an argument) then this will be the string # If a name is provided (as an argument) then this will be the string
# to place the cached attribute under if not then it will be the # to place the cached attribute under if not then it will be the
# function itself to be wrapped into a property. # function itself to be wrapped into a property.
@@ -365,10 +368,12 @@ class cachedproperty(object):
self.__doc__ = None self.__doc__ = None
def __call__(self, fget): def __call__(self, fget):
# If __init__ received a string then this will be the function to be # If __init__ received a string or a lock boolean then this will be
# wrapped as a property (if __init__ got a function then this will not # the function to be wrapped as a property (if __init__ got a
# be called). # function then this will not be called).
self._fget = fget self._fget = fget
if not self._attr_name:
self._attr_name = "_%s" % (fget.__name__)
self.__doc__ = getattr(fget, '__doc__', None) self.__doc__ = getattr(fget, '__doc__', None)
return self return self
@@ -387,13 +392,17 @@ class cachedproperty(object):
if hasattr(instance, self._attr_name): if hasattr(instance, self._attr_name):
return getattr(instance, self._attr_name) return getattr(instance, self._attr_name)
else: else:
with self._lock: if self._lock is not None:
try: self._lock.acquire()
return getattr(instance, self._attr_name) try:
except AttributeError: return getattr(instance, self._attr_name)
value = self._fget(instance) except AttributeError:
setattr(instance, self._attr_name, value) value = self._fget(instance)
return value setattr(instance, self._attr_name, value)
return value
finally:
if self._lock is not None:
self._lock.release()
def millis_to_datetime(milliseconds): def millis_to_datetime(milliseconds):