def decorator(fn): cache = LRUCache(maxsize) argspec = inspect2.getfullargspec(get_original_fn(fn)) arg_names = argspec.args[1:] + argspec.kwonlyargs # remove self async_fun = fn.asynq kwargs_defaults = get_kwargs_defaults(argspec) cache_key = key_fn if cache_key is None: def cache_key(args, kwargs): return get_args_tuple(args, kwargs, arg_names, kwargs_defaults) @asynq() @functools.wraps(fn) def wrapper(*args, **kwargs): key = cache_key(args, kwargs) try: result(cache[key]) return except KeyError: value = yield async_fun(*args, **kwargs) cache[key] = value result(value) return return wrapper
def memoize(fun): """Memoizes return values of the decorated function. Similar to l0cache, but the cache persists for the duration of the process, unless clear_cache() is called on the function. """ argspec = inspect2.getfullargspec(fun) arg_names = argspec.args + argspec.kwonlyargs kwargs_defaults = get_kwargs_defaults(argspec) def cache_key(args, kwargs): return get_args_tuple(args, kwargs, arg_names, kwargs_defaults) @functools.wraps(fun) def new_fun(*args, **kwargs): k = cache_key(args, kwargs) if k not in new_fun.__cache: new_fun.__cache[k] = fun(*args, **kwargs) return new_fun.__cache[k] def clear_cache(): """Removes all cached values for this function.""" new_fun.__cache.clear() new_fun.__cache = {} new_fun.clear_cache = clear_cache return new_fun
def cache_fun(fun): argspec = inspect2.getfullargspec(fun) arg_names = argspec.args[1:] + argspec.kwonlyargs # remove self kwargs_defaults = get_kwargs_defaults(argspec) cache = {} def cache_key(args, kwargs): return get_args_tuple(args, kwargs, arg_names, kwargs_defaults) def clear_cache(instance_key, ref): del cache[instance_key] @functools.wraps(fun) def new_fun(self, *args, **kwargs): instance_key = id(self) if instance_key not in cache: ref = weakref.ref(self, functools.partial(clear_cache, instance_key)) cache[instance_key] = (ref, {}) instance_cache = cache[instance_key][1] k = cache_key(args, kwargs) if k not in instance_cache: instance_cache[k] = fun(self, *args, **kwargs) return instance_cache[k] # just so unit tests can check that this is cleaned up correctly new_fun.__cached_per_instance_cache__ = cache return new_fun
def decorator(fn): cache = LRUCache(maxsize) argspec = inspect2.getfullargspec(fn) arg_names = argspec.args[1:] + argspec.kwonlyargs # remove self kwargs_defaults = get_kwargs_defaults(argspec) cache_key = key_fn if cache_key is None: def cache_key(args, kwargs): return get_args_tuple(args, kwargs, arg_names, kwargs_defaults) @functools.wraps(fn) def wrapper(*args, **kwargs): key = cache_key(args, kwargs) try: return cache[key] except KeyError: value = fn(*args, **kwargs) cache[key] = value return value wrapper.clear = cache.clear return wrapper
def decorator(fun): _keygetter = keygetter if _keygetter is None: original_fn = get_original_fn(fun) argspec = inspect2.getfullargspec(original_fn) arg_names = argspec.args + argspec.kwonlyargs kwargs_defaults = get_kwargs_defaults(argspec) _keygetter = lambda args, kwargs: get_args_tuple( args, kwargs, arg_names, kwargs_defaults) return decorate(DeduplicateDecorator, fun.task_cls, _keygetter)(fun)
def cache_fun(fun): argspec = inspect2.getfullargspec(fun) arg_names = argspec.args + argspec.kwonlyargs kwargs_defaults = get_kwargs_defaults(argspec) def cache_key(args, kwargs): return repr( get_args_tuple(args, kwargs, arg_names, kwargs_defaults)) @functools.wraps(fun) def new_fun(*args, **kwargs): k = cache_key(args, kwargs) current_time = int(time.time()) # k is not in the cache; perform the function and cache the result. if k not in new_fun.__cache or k not in new_fun.__cache_times: new_fun.__cache[k] = fun(*args, **kwargs) new_fun.__cache_times[k] = current_time return new_fun.__cache[k] # k is in the cache at this point. Check if the ttl has expired; # if so, recompute the value and cache it. cache_time = new_fun.__cache_times[k] if current_time - cache_time > ttl_secs: new_fun.__cache[k] = fun(*args, **kwargs) new_fun.__cache_times[k] = current_time # finally, return the cached result. return new_fun.__cache[k] def clear_cache(): """Removes all cached values for this function.""" new_fun.__cache.clear() new_fun.__cache_times.clear() def dirty(*args, **kwargs): """Dirties the function for a given set of arguments.""" k = cache_key(args, kwargs) new_fun.__cache.pop(k, None) new_fun.__cache_times.pop(k, None) new_fun.__cache = {} new_fun.__cache_times = {} new_fun.clear_cache = clear_cache new_fun.dirty = dirty return new_fun
def key(self, args=None): """ Returns the key that will uniquely identify a function even when it is overloaded :param args: the function :return: tuple of function specs """ if args is None: args = getfullargspec(self.fn).args return tuple([ self.fn.__module__, self.fn.__class__, self.fn.__name__, len(args or []), ])
def cache_fun(fun): argspec = inspect2.getfullargspec(get_original_fn(fun)) arg_names = argspec.args[1:] + argspec.kwonlyargs # remove self async_fun = fun.asynq kwargs_defaults = get_kwargs_defaults(argspec) cache = {} def cache_key(args, kwargs): return get_args_tuple(args, kwargs, arg_names, kwargs_defaults) def clear_cache(instance_key, ref): del cache[instance_key] @async_proxy() @functools.wraps(fun) def new_fun(self, *args, **kwargs): instance_key = id(self) if instance_key not in cache: ref = weakref.ref(self, functools.partial(clear_cache, instance_key)) cache[instance_key] = (ref, {}) instance_cache = cache[instance_key][1] k = cache_key(args, kwargs) try: return ConstFuture(instance_cache[k]) except KeyError: def callback(task): instance_cache[k] = task.value() task = async_fun(self, *args, **kwargs) task.on_computed.subscribe(callback) return task # just so unit tests can check that this is cleaned up correctly new_fun.__acached_per_instance_cache__ = cache return new_fun
def cache_fun(fun): argspec = inspect2.getfullargspec(get_original_fn(fun)) arg_names = argspec.args[1:] + argspec.kwonlyargs # remove self async_fun = fun.asynq kwargs_defaults = get_kwargs_defaults(argspec) cache = {} def cache_key(args, kwargs): return get_args_tuple(args, kwargs, arg_names, kwargs_defaults) def clear_cache(instance_key, ref): del cache[instance_key] @asynq() @functools.wraps(fun) def new_fun(self, *args, **kwargs): instance_key = id(self) if instance_key not in cache: ref = weakref.ref(self, functools.partial(clear_cache, instance_key)) cache[instance_key] = (ref, {}) instance_cache = cache[instance_key][1] k = cache_key(args, kwargs) try: result(instance_cache[k]) return except KeyError: value = yield async_fun(self, *args, **kwargs) instance_cache[k] = value result(value) return # just so unit tests can check that this is cleaned up correctly new_fun.__acached_per_instance_cache__ = cache return new_fun