本文目录导读:

Python 缓存优化需要根据缓存类型、数据特征和访问模式选择合适的策略,以下是系统性的优化方法,按效果从高到低排序:
数据压缩(最直接有效)
对象级压缩
import zlib
import pickle
def compress_and_cache(data):
# 压缩后存储
compressed = zlib.compress(pickle.dumps(data))
cache[key] = compressed
def get_from_cache(key):
compressed = cache[key]
return pickle.loads(zlib.decompress(compressed))
使用更高效的序列化
# 相比 pickle,msgpack 更紧凑
import msgpack
data = {"key": "value", "numbers": [1,2,3]}
packed = msgpack.packb(data) # 比 pickle 小 30-50%
合理选择缓存淘汰策略
from functools import lru_cache
import sys
# 限制缓存大小
@lru_cache(maxsize=128) # 只保留最近使用的128个结果
def expensive_function(n):
return n * n
# 自定义LRU缓存(比lru_cache更节省内存)
from collections import OrderedDict
class SizeLimitedCache:
def __init__(self, max_size_mb=100):
self.cache = OrderedDict()
self.max_size = max_size_mb * 1024 * 1024
self.current_size = 0
def set(self, key, value):
# 计算大小
size = sys.getsizeof(value)
# 如果单个值太大,不缓存
if size > self.max_size:
return
# 淘汰直到有足够空间
while self.current_size + size > self.max_size:
self.cache.popitem(last=False)
self.cache[key] = value
self.current_size += size
使用更高效的数据结构
替换字典为更紧凑的结构
# 使用 __slots__ 减少对象开销
class CacheEntry:
__slots__ = ['data', 'expires_at', 'size']
def __init__(self, data, expires_at):
self.data = data
self.expires_at = expires_at
self.size = sys.getsizeof(data)
# 使用数组代替字典(适用于整数键)
import array
cache = array.array('i') # 每个元素只占4字节
# 使用 blist 替代 list(大数据量时)
from blist import blist
cache = blist([None] * 1000) # 内存占用更稳定的链表
缓存分割和分片
# 将大缓存拆分成小缓存
class ShardedCache:
def __init__(self, num_shards=16):
self.shards = [{} for _ in range(num_shards)]
def _get_shard(self, key):
return self.shards[hash(key) % len(self.shards)]
def get(self, key):
return self._get_shard(key).get(key)
def set(self, key, value):
shard = self._get_shard(key)
# 只清理单个分片,而不是整个缓存
if len(shard) > 10000:
# 清理最旧的20%
for k in list(shard.keys())[:2000]:
del shard[k]
shard[key] = value
惰性加载和缓存预热
# 延迟初始化缓存
class LazyInitCache:
def __init__(self):
self._cache = None # 使用时才创建
@property
def cache(self):
if self._cache is None:
self._cache = {}
return self._cache
def get_or_compute(self, key, compute_func):
if key not in self.cache:
self.cache[key] = compute_func()
return self.cache[key]
使用专用缓存库
diskcache(磁盘缓存)
import diskcache as dc
# 使用磁盘缓存,内存占用极小
cache = dc.Cache('/tmp/my_cache')
cache.set('key', large_data, expire=3600) # 1小时后自动过期
Redis(分布式缓存)
import redis
r = redis.Redis(host='localhost', port=6379)
# Redis 支持内存优化
r.set('key', data, ex=3600) # 设置过期时间
内存复用
# 复用已分配的内存
class MemoryPool:
def __init__(self, size=1024):
self.pool = [bytearray(size) for _ in range(10)]
self.index = 0
def get_buffer(self):
buffer = self.pool[self.index]
self.index = (self.index + 1) % len(self.pool)
return buffer[:0] # 重置但保留内存
# 对象池
from collections import deque
class ObjectPool:
def __init__(self, cls, max_size=100):
self.pool = deque(maxlen=max_size)
self.cls = cls
def acquire(self):
return self.pool.pop() if self.pool else self.cls()
def release(self, obj):
self.pool.append(obj)
监控和调优工具
import tracemalloc
# 跟踪内存使用
tracemalloc.start()
# 分析缓存大小
def analyze_cache(cache):
total_size = 0
for key, value in cache.items():
size = sys.getsizeof(value)
total_size += size
print(f"Key: {key}, Size: {size/1024:.2f}KB")
print(f"Total: {total_size/1024/1024:.2f}MB")
# 使用 memory_profiler
# pip install memory_profiler
from memory_profiler import profile
@profile
def test_cache():
cache = {}
for i in range(10000):
cache[i] = "x" * 1000
实际优化案例
# 优化前的缓存
class BasicCache:
def __init__(self):
self.cache = {}
def set(self, key, value):
self.cache[key] = value # 没有限制,内存无限增长
# 优化后的缓存
class OptimizedCache:
def __init__(self, max_memory_mb=500, ttl_seconds=3600):
self.cache = {}
self.max_memory = max_memory_mb * 1024 * 1024
self.ttl = ttl_seconds
self.current_memory = 0
self.timestamps = {}
def set(self, key, value, compress=True):
# 1. 数据压缩
if compress:
value = zlib.compress(pickle.dumps(value))
size = sys.getsizeof(value)
# 2. 如果单个值太大,不缓存
if size > self.max_memory * 0.1:
return
# 3. 淘汰策略
while self.current_memory + size > self.max_memory:
oldest_key = min(self.timestamps, key=self.timestamps.get)
self._remove(oldest_key)
# 4. 存储
self.cache[key] = value
self.timestamps[key] = time.time()
self.current_memory += size
def get(self, key):
# 5. TTL 检查
if key in self.timestamps:
if time.time() - self.timestamps[key] > self.ttl:
self._remove(key)
return None
value = self.cache.get(key)
if value:
return pickle.loads(zlib.decompress(value))
return None
def _remove(self, key):
if key in self.cache:
self.current_memory -= sys.getsizeof(self.cache[key])
del self.cache[key]
del self.timestamps[key]
关键优化建议
- 先测量后优化:使用
sys.getsizeof()和tracemalloc了解缓存实际占用 - 缓存不可变数据:使用
tuple代替list,frozenset代替set - 避免缓存大对象:如果数据大于10MB,考虑分片存储
- 设置合理的TTL:不要让数据在缓存中停留过久
- 使用引用计数:
weakref可以让对象在无引用时自动释放
选择哪种优化方法取决于你的具体场景:数据量、访问频率、修改频率、硬件资源等,最有效的方式往往是组合多种策略。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播