(func)
| 12 | |
| 13 | def timed_async_cache(expiration, condition=lambda x: True): |
| 14 | def decorator(func): |
| 15 | cache = {} |
| 16 | locks = {} |
| 17 | |
| 18 | @wraps(func) |
| 19 | async def wrapper(*args): |
| 20 | current_time = time.time() |
| 21 | # 如果是类方法,args[0]是实例,我们获取类名 |
| 22 | if args and hasattr(args[0], "__class__"): |
| 23 | cache_key = f"{args[0].__class__.__name__}.{func.__name__}" |
| 24 | else: |
| 25 | cache_key = func.__name__ |
| 26 | |
| 27 | # 为每个缓存键创建一个锁 |
| 28 | if cache_key not in locks: |
| 29 | locks[cache_key] = asyncio.Lock() |
| 30 | |
| 31 | # 检查缓存,如果有效则直接返回 |
| 32 | if cache_key in cache: |
| 33 | value, timestamp = cache[cache_key] |
| 34 | if current_time - timestamp < expiration: |
| 35 | return value |
| 36 | |
| 37 | # 获取锁以确保并发安全 |
| 38 | async with locks[cache_key]: |
| 39 | # 双重检查,避免等待锁期间其他协程已经更新了缓存 |
| 40 | if cache_key in cache: |
| 41 | value, timestamp = cache[cache_key] |
| 42 | if current_time - timestamp < expiration: |
| 43 | return value |
| 44 | |
| 45 | # 执行原始函数 |
| 46 | value = await func(*args) |
| 47 | if condition(value): |
| 48 | cache[cache_key] = (value, current_time) |
| 49 | return value |
| 50 | |
| 51 | return wrapper |
| 52 | |
| 53 | return decorator |
| 54 |
nothing calls this directly
no outgoing calls
no test coverage detected