52 lines
1.5 KiB
Python
52 lines
1.5 KiB
Python
from __future__ import annotations
|
|
|
|
import threading
|
|
import time
|
|
from typing import Callable, Generic, TypeVar
|
|
|
|
|
|
# 泛型参数表示缓存中实际保存的数据类型。
|
|
T = TypeVar("T")
|
|
|
|
|
|
class TTLCache(Generic[T]):
|
|
# 初始化一个简单的 TTL 缓存。
|
|
def __init__(self, ttl_seconds: float) -> None:
|
|
# 保存缓存 TTL。
|
|
self.ttl_seconds = ttl_seconds
|
|
# 用锁保护并发访问。
|
|
self._lock = threading.Lock()
|
|
# 初始时没有缓存内容。
|
|
self._payload: T | None = None
|
|
# 初始构建时间为 0。
|
|
self._built_at = 0.0
|
|
|
|
# 按需获取缓存,过期时重新构建。
|
|
def get_or_build(self, builder: Callable[[], T]) -> T:
|
|
# 记录当前时间。
|
|
now = time.time()
|
|
|
|
# 先在锁内尝试读取缓存。
|
|
with self._lock:
|
|
# 有缓存且未过期时直接返回。
|
|
if self._payload is not None and now - self._built_at < self.ttl_seconds:
|
|
return self._payload
|
|
|
|
# 锁外构建新数据,避免长时间占锁。
|
|
payload = builder()
|
|
|
|
# 再次进入锁,把新结果写回去。
|
|
with self._lock:
|
|
self._payload = payload
|
|
self._built_at = now
|
|
|
|
# 返回新构建的结果。
|
|
return payload
|
|
|
|
# 主动清空缓存。
|
|
def clear(self) -> None:
|
|
# 在锁内重置缓存状态。
|
|
with self._lock:
|
|
self._payload = None
|
|
self._built_at = 0.0
|