常见的 2 中缓存
ttl_cache
通常指的是带有 TTL(Time-To-Live,生存时间) 的缓存机制,即缓存的数据在指定的时间后会自动失效。这种缓存策略广泛应用于各种场景,如 Web 开发、数据库查询优化、API 调用等,以提高性能并减少重复计算或网络请求。
1. TTL 的含义
- TTL(Time-To-Live):表示缓存项的有效时间。一旦超过这个时间,缓存项将被视为过期,下次请求时需要重新生成或获取数据。
- 例如,设置一个缓存的 TTL 为 60 秒,意味着该缓存项在 60 秒后失效,之后的请求将重新计算或从源获取数据。
2. 常见的 ttl_cache
实现
Python 中的 cachetools
库
cachetools
是一个常用的 Python 缓存库,提供了多种缓存策略,包括基于 TTL 的缓存。
安装
pip install cachetools
示例代码
from cachetools import TTLCache
import time# 创建一个最多存储 100 个条目,TTL 为 60 秒的缓存
cache = TTLCache(maxsize=100, ttl=60)def get_data(key):if key in cache:print("从缓存中获取数据")return cache[key]else:print("计算数据并存入缓存")# 模拟耗时操作data = f"数据_{key}_{int(time.time())}"cache[key] = datareturn data# 测试
print(get_data("test")) # 第一次调用,计算数据
time.sleep(2)
print(get_data("test")) # 第二次调用,从缓存中获取
装饰器形式的 ttl_cache
cachetools
还提供了装饰器形式的 @ttl_cache
,可以更方便地为函数添加缓存。
from cachetools import ttl_cache
import time@ttl_cache(ttl=60, maxsize=100)
def get_user_info(user_id):print(f"查询用户 {user_id} 的信息")# 模拟耗时操作time.sleep(1)return {"user_id": user_id, "name": "张三", "timestamp": int(time.time())}# 测试
print(get_user_info(1)) # 第一次调用,查询用户信息
print(get_user_info(1)) # 第二次调用,从缓存中获取
3. 其他语言和框架中的 ttl_cache
JavaScript/Node.js
在 Node.js 中,可以使用 node-cache
或 memory-cache
等库实现 TTL 缓存。
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 60 }); // TTL 60 秒function getData(key) {const cached = cache.get(key);if (cached) {console.log('从缓存中获取数据');return cached;} else {console.log('计算数据并存入缓存');const data = `数据_${key}_${Date.now()}`;cache.set(key, data);return data;}
}console.log(getData('test')); // 第一次调用,计算数据
setTimeout(() => console.log(getData('test')), 2000); // 第二次调用,从缓存中获取
Redis
Redis 是一个流行的内存数据结构存储,支持 TTL 缓存。
import redis
import jsonr = redis.Redis(host='localhost', port=6379, db=0)def get_data(key):cached = r.get(key)if cached:print("从 Redis 缓存中获取数据")return json.loads(cached)else:print("计算数据并存入 Redis 缓存")data = {"key": key, "value": f"数据_{key}_{int(time.time())}"}r.setex(key, 60, json.dumps(data)) # TTL 60 秒return dataprint(get_data("test")) # 第一次调用,计算数据
time.sleep(2)
print(get_data("test")) # 第二次调用,从缓存中获取
✅ 方法 1:使用 ex
参数(秒)
r = redis.Redis(host='localhost', port=6379, db=0)
r.set('my_key', 'my_value', ex=60) # ex=60 表示 60 秒后过期
✅ 方法 2:使用 px
参数(毫秒)
r.set('my_key', 'my_value', px=60000) # 60000 毫秒 = 60 秒
4. 应用场景
- Web API 缓存:避免频繁调用外部 API,减少响应时间。
- 数据库查询缓存:缓存复杂的查询结果,减少数据库负载。
- 会话管理:存储用户会话信息,设置合理的过期时间。
- 配置管理:缓存配置信息,避免频繁读取文件或数据库。
5. 注意事项
- 内存管理:TTL 缓存会占用内存,需合理设置
maxsize
和ttl
,避免内存泄漏。 - 一致性:缓存数据可能与源数据不一致,特别是在数据频繁更新的场景下。
- 并发问题:在高并发环境下,多个请求可能同时触发缓存失效和重新计算,需考虑使用锁或其他同步机制。
💡 额外建议
1. 使用连接池(生产推荐)
from redis import ConnectionPoolpool = ConnectionPool(host='localhost', port=6379, db=0)
r = redis.Redis(connection_pool=pool)
避免每次创建新连接。
2. 处理序列化(存字典、列表等)
Redis 只能存字节或字符串,所以复杂数据要序列化:
import jsondata = {'name': 'Alice', 'age': 30}
r.set('user:1', json.dumps(data), ex=300)# 读取时反序列化
raw = r.get('user:1')
user = json.loads(raw) if raw else None
3. 异常处理
import redistry:r = redis.Redis(host='localhost', port=6379, db=0, socket_connect_timeout=2)r.set('test', 'value', ex=60)
except redis.ConnectionError:print("Redis 连接失败")
except Exception as e:print(f"其他错误: {e}")
通过合理使用 ttl_cache
,可以显著提升应用的性能和用户体验。
=========================
functools.lru_cache
是 Python 标准库中一个非常实用的装饰器(decorator),用于为函数添加 LRU 缓存(Least Recently Used Cache) 功能。
它的作用是:
缓存函数的返回值,避免重复计算,提升性能。
🚀 一、基本用法
from functools import lru_cache@lru_cache(maxsize=128)
def fibonacci(n):if n < 2:return nreturn fibonacci(n-1) + fibonacci(n-2)print(fibonacci(100)) # 第一次计算,结果会被缓存
print(fibonacci(100)) # 第二次直接从缓存返回,速度极快 ✅
🔍 二、参数详解
@lru_cache(maxsize=128, typed=False)
参数 | 说明 |
---|---|
maxsize | 缓存的最大条目数。默认 128 ,设为 None 表示无限制 |
typed | 是否区分参数类型。True 时,fibonacci(3.0) 和 fibonacci(3) 被视为不同调用 |
示例:typed=True
的影响
@lru_cache(maxsize=32, typed=True)
def add(x, y):print(f"计算 {x} + {y}")return x + yadd(1, 2) # 计算 1 + 2
add(1.0, 2.0) # 再次计算,因为 1.0 和 1 类型不同(float vs int)
🧠 三、工作原理
- 缓存键(Cache Key):基于函数的位置参数和关键字参数生成。
- LRU 策略:当缓存满时,最近最少使用(Least Recently Used) 的条目会被清除。
- 存储位置:在函数的内存中(属于该函数对象的一部分)。
✅ 四、适用场景(适合缓存的函数)
纯函数(Pure Function)
- 相同输入 → 相同输出
- 无副作用(不修改全局状态)
计算密集型
- 递归、数学计算、复杂逻辑
频繁调用且参数重复
- 如 API 调用封装、数据库查询(简单场景)
⚠️ 五、不适用场景(慎用!)
场景 | 问题 |
---|---|
函数有副作用 | 缓存后不会再次执行,副作用丢失 |
返回可变对象(如 list、dict) | 多次调用返回同一个对象,修改会影响其他调用 |
参数是不可哈希类型 | 如 list , dict , set 会报错 TypeError: unhashable type |
多线程/多进程共享问题 | 缓存是线程安全的,但每个进程有自己的缓存副本 |
❌ 错误示例:
@lru_cache
def get_data():return {'time': time.time()} # ❌ 返回可变字典,且时间会变
📊 六、性能监控(高级用法)
lru_cache
提供了 .cache_info()
和 .cache_clear()
方法:
@lru_cache(maxsize=32)
def square(n):return n * nsquare(2)
square(3)
square(2) # 命中缓存print(square.cache_info())
# 输出:CacheInfo(hits=1, misses=2, maxsize=32, currsize=2)square.cache_clear() # 手动清空缓存
🆚 七、与 cachetools.ttl_cache
对比
特性 | functools.lru_cache | cachetools.ttl_cache |
---|---|---|
是否标准库 | ✅ 是 | ❌ 需安装 pip install cachetools |
过期机制 | LRU(按使用频率) | TTL(按时间) |
是否支持过期时间 | ❌ 不支持 | ✅ 支持 ttl=60 秒 |
多进程共享 | ❌ 每个进程独立 | ❌ 同样独立(除非用 Redis) |
适合场景 | 纯计算、递归 | API 缓存、数据库查询、有时效性要求 |
✅ 八、最佳实践建议
- 优先用于纯函数:无副作用、输入输出确定。
- 设置合理的
maxsize
:避免内存泄漏。 - 避免缓存可变对象:返回
tuple
而不是list
。 - 在数据变化时手动清除缓存(如果有依赖):
square.cache_clear() # 清除所有缓存
- 生产环境复杂缓存用 Redis:
lru_cache
只适合单进程、无持久化需求的场景。
🎯 总结
问题 | 回答 |
---|---|
lru_cache 是什么? | Python 内置的 LRU 缓存装饰器 |
适合什么函数? | 纯函数、计算密集型、参数可哈希 |
缓存会自动更新吗? | ❌ 不会,除非手动清除或 LRU 淘汰 |
重启后还存在吗? | ❌ 不存在,存储在内存中 |
生产环境能用吗? | ✅ 可以,但复杂场景建议用 Redis |
==============================
django.core.cache
是 Django 框架中用于缓存系统的核心模块。它提供了一套统一的 API,让你可以轻松地在 Django 项目中使用各种缓存后端(如内存、Redis、数据库等),从而大幅提升网站性能。
🚀 一、为什么要用缓存?
在 Web 开发中,有些操作很耗时,比如:
- 复杂的数据库查询
- 调用外部 API
- 渲染大型模板
缓存的作用就是:
把结果存起来,下次直接用,避免重复计算或请求
📦 二、django.core.cache
能干什么?
它提供了:
- 统一的缓存 API
- 支持多种缓存后端
- 视图缓存、模板片段缓存、低级缓存 API
- 过期时间(TTL)支持
🔧 三、如何配置(settings.py)
首先在 settings.py
中配置缓存后端:
# settings.pyCACHES = {'default': {'BACKEND': 'django.core.cache.backends.redis.RedisCache', # Redis'LOCATION': 'redis://127.0.0.1:6379/1','TIMEOUT': 300, # 缓存默认超时时间(秒),默认 300'OPTIONS': {'CLIENT_CLASS': 'django_redis.client.DefaultClient',}},'local': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', # 本地内存'LOCATION': 'unique-snowflake',}
}# 可选:设置默认缓存
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 600
CACHE_MIDDLEWARE_KEY_PREFIX = 'mysite'
⚠️ 如果你用 Redis,需要安装:
pip install django-redis
🛠 四、常用缓存后端
后端 | 说明 | 是否推荐 |
---|---|---|
redis.RedisCache | Redis 缓存(高性能,生产推荐) | ✅ 强烈推荐 |
locmem.LocMemCache | 本地内存缓存(开发用) | ✅ 开发 |
filebased.FileBasedCache | 文件系统缓存 | ⚠️ 性能差 |
db.DatabaseCache | 数据库表缓存 | ⚠️ 一般不用 |
memcached.PyMemcacheCache | Memcached | ✅ 生产可用 |
💡 五、使用方式
1. 低级缓存 API(最灵活)
from django.core.cache import cache# 写入缓存
cache.set('my_key', 'Hello, Cache!', timeout=60) # 60秒后过期# 读取缓存
value = cache.get('my_key') # 'Hello, Cache!'
value = cache.get('not_exist', 'default') # 如果不存在,返回默认值# 删除缓存
cache.delete('my_key')# 批量操作
cache.set_many({'a': 1, 'b': 2})
values = cache.get_many(['a', 'b']) # {'a': 1, 'b': 2}# 设置过期时间
cache.set('user_1', user_data, 300) # 5分钟
2. 视图缓存(缓存整个页面)
from django.views.decorators.cache import cache_page@cache_page(60 * 15) # 缓存 15 分钟
def my_view(request):# 复杂查询或渲染return render(request, 'my_template.html')
URL 每次访问都会从缓存返回,直到过期。
3. 模板片段缓存
{% load cache %}<!-- 缓存这个片段 500 秒 -->
{% cache 500 user_info user.id %}<div><h1>{{ user.name }}</h1><p>{{ user.profile.bio }}</p></div>
{% endcache %}
如果
user.id
变了,缓存也会更新(因为它是缓存键的一部分)。
4. 缓存用户特定内容
# 使用 vary_on_cookie 或 vary_on_headers
from django.views.decorators.cache import cache_page
from django.views.decorators.vary import vary_on_cookie@cache_page(60)
@vary_on_cookie
def user_dashboard(request):# 不同用户的缓存是分开的return render(request, 'dashboard.html')
🔄 六、缓存键(Cache Key)生成
Django 会自动为每个缓存生成唯一的 key,比如:
- 视图缓存:
views.decorators.cache.cache_page.{hash}.{path}.{lang}
- 低级缓存:你指定的 key(如
'my_key'
)
你也可以自定义 key 生成函数:
def make_key(key, key_prefix, version):return f'{key_prefix}:{version}:{key}'CACHES = {'default': {'BACKEND': '...','KEY_FUNCTION': 'myapp.utils.make_key',}
}
🧹 七、清除缓存
# 删除单个 key
cache.delete('my_key')# 删除多个
cache.delete_many(['key1', 'key2'])# 清空所有(慎用!)
cache.clear()# 删除带前缀的 key(需要 django-redis)
from django.core.cache import caches
cache = caches['default']
cache.delete_pattern('user_*') # 删除所有 user_ 开头的 key
✅ 八、最佳实践
建议 | 说明 |
---|---|
✅ 生产用 Redis | 性能好,支持 TTL,多进程共享 |
✅ 设置合理的 TIMEOUT | 不要太长(数据过期),不要太短(失去缓存意义) |
✅ 在数据变更时主动清除缓存 | 避免脏数据 |
✅ 使用 cache.get_or_set() | 原子操作,更安全 |
# 推荐写法
data = cache.get_or_set('expensive_data', compute_expensive_data, 300)
🎯 总结
功能 | 方法 |
---|---|
缓存数据 | cache.set(key, value, timeout) |
获取数据 | cache.get(key, default) |
删除数据 | cache.delete(key) |
缓存整个页面 | @cache_page(60) |
缓存模板片段 | {% cache 60 name %} |
生产推荐后端 | Redis |
django.core.cache
是 Django 性能优化的核心工具之一。掌握它,你的网站速度会快上好几倍!