本文目录导读:
- 最简单的:字典缓存(手动实现)
- 带过期时间的缓存(TTL)
- 使用
functools.lru_cache(标准库,最推荐) - 使用第三方库
cachetools(功能最丰富) - 使用
diskcache(持久化到磁盘,进程重启不丢失) - 总结:如何选择?
Python 实现本地缓存的案例非常多,根据你的需求复杂度不同,可以从最简单的字典缓存到使用标准库 functools.lru_cache,再到使用第三方库如 cachetools 或 diskcache。
下面我为你整理了 5种不同场景的本地缓存实现案例,从简单到复杂,覆盖内存缓存和磁盘缓存。
最简单的:字典缓存(手动实现)
适用场景:临时存储少量数据,进程退出即失效。
import time
# 全局缓存字典
cache = {}
def get_data_from_database(key):
"""模拟一个耗时的数据库查询"""
print(f" 正在查询数据库: {key}")
time.sleep(2) # 模拟耗时
return f"数据_{key}"
def get_data(key):
"""带缓存的获取函数"""
if key not in cache:
cache[key] = get_data_from_database(key)
else:
print(f" 缓存命中: {key}")
return cache[key]
# 测试
print(get_data("user_1")) # 第一次,查询数据库
print(get_data("user_1")) # 第二次,缓存命中
输出:
正在查询数据库: user_1
数据_user_1
缓存命中: user_1
数据_user_1
带过期时间的缓存(TTL)
适用场景:数据需要定期刷新,比如从API获取的token或天气数据。
import time
class TTLCache:
def __init__(self, ttl_seconds=10):
self.cache = {}
self.ttl = ttl_seconds
def get(self, key):
"""获取缓存,如果过期返回None"""
if key in self.cache:
value, timestamp = self.cache[key]
if time.time() - timestamp < self.ttl:
return value
else:
del self.cache[key] # 删除过期数据
return None
def set(self, key, value):
self.cache[key] = (value, time.time())
# 使用示例
cache = TTLCache(ttl_seconds=5)
# 模拟存储
cache.set("weather", "晴天")
print(cache.get("weather")) # 输出: 晴天
time.sleep(6) # 等待超过5秒
print(cache.get("weather")) # 输出: None(过期了)
使用 functools.lru_cache(标准库,最推荐)
适用场景:对纯函数进行缓存,计算密集型任务(如斐波那契、递归、复杂计算)。
from functools import lru_cache
import time
@lru_cache(maxsize=128) # 最多缓存128个结果
def expensive_computation(n):
"""模拟一个耗时的计算"""
print(f" 正在计算 {n}...")
time.sleep(1)
return n * n
# 测试
print(expensive_computation(5)) # 计算,输出25
print(expensive_computation(5)) # 直接返回缓存,不打印"正在计算"
print(expensive_computation(10)) # 计算新值
关键特性:
maxsize:缓存大小,设为None则无限制(小心内存溢出)- LRU(Least Recently Used)淘汰策略:当缓存满时,淘汰最久未使用的数据
- 函数参数必须可哈希(不可用list、dict作为参数)
查看缓存状态:
print(expensive_computation.cache_info()) # 输出: CacheInfo(hits=1, misses=2, maxsize=128, currsize=2)
使用第三方库 cachetools(功能最丰富)
适用场景:需要TTL、不同淘汰策略(LFU、FIFO、LRU)、更精细控制。
安装:
pip install cachetools
案例:带TTL的缓存
from cachetools import TTLCache
import time
# 创建缓存:最大容量100,TTL 10秒
cache = TTLCache(maxsize=100, ttl=10)
# 像字典一样使用
cache["key1"] = "value1"
print(cache["key1"]) # 输出: value1
time.sleep(11)
print("key1" in cache) # 输出: False(过期了)
不同淘汰策略:
from cachetools import LRUCache, LFUCache, FIFOCache # LRU: 最近最少使用(推荐通用) lru_cache = LRUCache(maxsize=100) # LFU: 使用频率最少 lfu_cache = LFUCache(maxsize=100) # FIFO: 先进先出 fifo_cache = FIFOCache(maxsize=100)
使用 diskcache(持久化到磁盘,进程重启不丢失)
适用场景:数据量大、跨进程共享、程序重启后仍需保留。
安装:
pip install diskcache
from diskcache import Cache
import time
# 创建一个磁盘缓存目录
cache = Cache("./my_cache_dir")
# 存入数据(可以设置过期时间)
cache.set("user_profile", {"name": "Alice", "age": 30}, expire=60*60) # 1小时过期
# 获取数据
profile = cache.get("user_profile")
print(profile) # 输出: {'name': 'Alice', 'age': 30}
# 即使程序重启,数据还在(只要不删除目录)
print(len(cache)) # 查看缓存条目数
高级用法:作为装饰器自动缓存函数结果
from diskcache import Cache
cache = Cache("./cache")
@cache.memoize(expire=600) # 自动缓存函数返回值,10分钟过期
def fetch_weather(city):
# 假设这里是一个HTTP请求
time.sleep(3)
return f"{city}的天气: 晴天"
print(fetch_weather("北京")) # 第一次:慢
print(fetch_weather("北京")) # 第二次:瞬间返回(缓存)
如何选择?
| 需求 | 推荐方案 |
|---|---|
| 临时小数据,代码简单 | 字典 + 手动管理 |
| 函数计算结果,少量参数 | functools.lru_cache |
| 需要TTL过期、多种淘汰策略 | cachetools |
| 数据量大、跨进程、需持久化 | diskcache |
| 读写频繁、高并发场景 | 考虑 Redis 或 Memcached(本地缓存不够) |
对于大多数 Python 应用场景,functools.lru_cache 是最简单高效的入门选择,而 cachetools 提供了更专业、更灵活的控制。
标签: ttl