From b033fa672227720ae64bca25eafffc87d5fea42a Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Mon, 8 Feb 2016 23:16:58 -0800 Subject: [PATCH] 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 --- taskflow/utils/misc.py | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/taskflow/utils/misc.py b/taskflow/utils/misc.py index 5c2bf4fa..3798a457 100644 --- a/taskflow/utils/misc.py +++ b/taskflow/utils/misc.py @@ -350,8 +350,11 @@ class cachedproperty(object): cached property would be stored under '_get_thing' in the self object after the first call to 'get_thing' occurs. """ - def __init__(self, fget): - self._lock = threading.RLock() + def __init__(self, fget=None, require_lock=True): + 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 # to place the cached attribute under if not then it will be the # function itself to be wrapped into a property. @@ -365,10 +368,12 @@ class cachedproperty(object): self.__doc__ = None def __call__(self, fget): - # If __init__ received a string then this will be the function to be - # wrapped as a property (if __init__ got a function then this will not - # be called). + # If __init__ received a string or a lock boolean then this will be + # the function to be wrapped as a property (if __init__ got a + # function then this will not be called). self._fget = fget + if not self._attr_name: + self._attr_name = "_%s" % (fget.__name__) self.__doc__ = getattr(fget, '__doc__', None) return self @@ -387,13 +392,17 @@ class cachedproperty(object): if hasattr(instance, self._attr_name): return getattr(instance, self._attr_name) else: - with self._lock: - try: - return getattr(instance, self._attr_name) - except AttributeError: - value = self._fget(instance) - setattr(instance, self._attr_name, value) - return value + if self._lock is not None: + self._lock.acquire() + try: + return getattr(instance, self._attr_name) + except AttributeError: + value = self._fget(instance) + setattr(instance, self._attr_name, value) + return value + finally: + if self._lock is not None: + self._lock.release() def millis_to_datetime(milliseconds):