Skip to content

Instantly share code, notes, and snippets.

@thevickypedia
Created December 4, 2023 20:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thevickypedia/6627ecfa7182a13b75cc7469e7e68ea2 to your computer and use it in GitHub Desktop.
Save thevickypedia/6627ecfa7182a13b75cc7469e7e68ea2 to your computer and use it in GitHub Desktop.
Timed caching using LRU algorithm
import functools
import time
def timed_cache(max_age, maxsize=128, typed=False):
"""Least-recently-used cache decorator with time-based cache invalidation.
See Also:
- ``lru_cache`` takes all params of the function and creates a key
- If even one key is changed, it will map to new entry thus refreshed.
- This is just a trick to force lrc_cache lib to provide TTL on top of max size.
- Uses ``time.monotonic`` since ``time.time`` relies on the system clock and may not be monotonic
- It's not guaranteed to always increase, it may in fact decrease if the machine syncs its system clock over a network
Args:
max_age: Time to live for cached results (in seconds).
maxsize: Maximum cache size (see `functools.lru_cache`).
typed: Cache on distinct input types (see `functools.lru_cache`).
"""
def _decorator(fn):
@functools.lru_cache(maxsize=maxsize, typed=typed)
def _new(*args, __timed_hash, **kwargs):
return fn(*args, **kwargs)
@functools.wraps(fn)
def _wrapped(*args, **kwargs):
return _new(*args, **kwargs, __timed_hash=int(time.monotonic() / max_age))
return _wrapped
return _decorator
def caller():
print('called')
return 10
@timed_cache(3)
def expensive():
return caller()
for _ in range(10):
print(expensive())
time.sleep(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment