def acquire(self): """Acquire semaphore by decrementing value using spin-lock algorithm.""" whileTrue: with self._cache.transact(retry=True):
value = self._cache.get(self._key, default=self._value) if value > 0:
self._cache.set(
self._key,
value - 1,
expire=self._expire,
tag=self._tag,
) return
time.sleep(0.001)
def release(self): """Release semaphore by incrementing value.""" with self._cache.transact(retry=True):
value = self._cache.get(self._key, default=self._value) assert self._value > value, 'cannot release un-acquired semaphore'
value += 1
self._cache.set(
self._key,
value,
expire=self._expire,
tag=self._tag,
)
def __enter__(self):
self.acquire()
def __exit__(self, *exc_info):
self.release()
def throttle(
cache,
count,
seconds,
name=None,
expire=None,
tag=None,
time_func=time.time,
sleep_func=time.sleep,
): """Decorator to throttle calls to function.
Assumes keys will not be evicted. Set the eviction policy to 'none' on the
cache to guarantee the keys are not evicted.
>>> import diskcache, time
>>> cache = diskcache.Cache()
>>> count = 0
>>> @throttle(cache, 2, 1) # 2 calls per 1 second
... def increment():
... global count
... count += 1
>>> start = time.time()
>>> while (time.time() - start) <= 2:
... increment()
>>> count in (6, 7) # 6 or 7 calls depending on CPU load True
"""
def decorator(func):
rate = count / float(seconds)
key = full_name(func) if name isNoneelse name
now = time_func()
cache.set(key, (now, count), expire=expire, tag=tag, retry=True)
@functools.wraps(func) def wrapper(*args, **kwargs): whileTrue: with cache.transact(retry=True):
last, tally = cache.get(key)
now = time_func()
tally += (now - last) * rate
delay = 0
Cache stampedes are a type of system overload that can occur when parallel
computing systems using memoization come under heavy load. This behaviour is sometimes also called dog-piling, cache miss storm, cache choking, or
the thundering herd problem.
The memoization decorator implements cache stampede protection through
early recomputation. Early recomputation of function results will occur
probabilistically before expiration in a background thread of
execution. Early probabilistic recomputation is based on research by
Vattani, A.; Chierichetti, F.; Lowenstein, K. (2015), Optimal Probabilistic
Cache Stampede Prevention, VLDB, pp. 886-897, ISSN 2150-8097
If name is set to None (default), the callable name will be determined
automatically.
If typed is set to True, function arguments of different types will be
cached separately. For example, f(3) and f(3.0) will be treated as distinct
calls with distinct results.
The original underlying function is accessible through the `__wrapped__`
attribute. This is useful for introspection, for bypassing the cache, or for rewrapping the function with a different cache.
An additional `__cache_key__` attribute can be used to generate the cache
key used for the given arguments.
>>> key = fib.__cache_key__(100)
>>> del cache[key]
Remember to call memoize when decorating a callable. If you forget, then a
TypeError will occur.
:param cache: cache to store callable arguments andreturn values
:param float expire: seconds until arguments expire
:param str name: name given for callable (default None, automatic)
:param bool typed: cache different types separately (default False)
:param str tag: text to associate with arguments (default None)
:param set ignore: positional or keyword args to ignore (default ())
:return: callable decorator
""" # Caution: Nearly identical code exists in Cache.memoize def decorator(func): """Decorator created by memoize call for callable."""
base = (full_name(func),) if name isNoneelse (name,)
def timer(*args, **kwargs): """Time execution of `func` and return result and time delta."""
start = time.time()
result = func(*args, **kwargs)
delta = time.time() - start return result, delta
@functools.wraps(func) def wrapper(*args, **kwargs): """Wrapper for callable to cache arguments and return values."""
key = wrapper.__cache_key__(*args, **kwargs)
pair, expire_time = cache.get(
key,
default=ENOVAL,
expire_time=True,
retry=True,
)
if pair isnot ENOVAL:
result, delta = pair
now = time.time()
ttl = expire_time - now
if (-delta * beta * math.log(random.random())) < ttl: return result # Cache hit.
# Check whether a thread has started for early recomputation.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.