Python 2.7中如何获取@ring.lru装饰静态方法的缓存统计?
解决方案:获取ring LRU缓存的统计数据(类似functools.lru_cache的cache_info)
我之前在Python 2.7里用ring库的时候也碰到过这个问题——明明知道内部在统计命中/未命中,但就是拿不到数据。下面给你几个实用的解决办法,从简单到稳妥都有:
方法1:直接访问ring缓存的内部统计属性
ring的LRU缓存实现里,存储实例(storage)有一个私有字典_stats,专门记录缓存的命中、未命中次数。你可以直接通过装饰后的函数对象访问它:
# 假设你的静态方法定义在某个类中,比如MyClass class MyClass: @ring.lru() @staticmethod def get_hostname_by_id(object_id): return Monkey.get_single_monkey_by_id(object_id).hostname # 获取缓存统计数据 cache_storage = MyClass.get_hostname_by_id.storage hits = cache_storage._stats.get('hit', 0) misses = cache_storage._stats.get('miss', 0) total_calls = hits + misses print "Cache hits: {}, misses: {}, total calls: {}".format(hits, misses, total_calls)
⚠️ 注意:这依赖于ring的内部实现细节(_stats私有属性),如果你的ring版本更新,这个属性可能会变化。我在ring 0.14.0(Python2.7支持的较新版本)里测试是有效的。
方法2:给缓存函数添加自定义的cache_info方法
为了用起来更像标准库的functools.lru_cache,可以给装饰后的方法加一个cache_info方法,返回结构化的统计数据:
class MyClass: @ring.lru() @staticmethod def get_hostname_by_id(object_id): return Monkey.get_single_monkey_by_id(object_id).hostname # 定义cache_info方法,模仿标准库的格式 def cache_info(): storage = MyClass.get_hostname_by_id.storage hits = storage._stats.get('hit', 0) misses = storage._stats.get('miss', 0) currsize = len(storage._cache) # 当前缓存的条目数 # 返回和functools.lru_cache.cache_info()类似的元组:(hits, misses, maxsize, currsize) return (hits, misses, storage.maxsize, currsize) # 把方法绑定到缓存函数上 MyClass.get_hostname_by_id.cache_info = cache_info # 调用方式和标准库完全一样: info = MyClass.get_hostname_by_id.cache_info() print "Hits: {}, Misses: {}, Max size: {}, Current size: {}".format(*info)
方法3:自己包装一层,不依赖ring内部实现
如果担心私有属性不稳定,你可以自己写一个简单的包装器,手动统计命中和未命中:
def track_cache_stats(cached_func): hits = [0] # 用列表是因为Python2.7里闭包不能修改外部变量,列表是可变对象 misses = [0] def wrapper(*args, **kwargs): # 先检查缓存键是否存在 cache_key = cached_func._get_key(*args, **kwargs) if cached_func.storage.exists(cache_key): hits[0] += 1 else: misses[0] += 1 return cached_func(*args, **kwargs) def cache_info(): return { 'hits': hits[0], 'misses': misses[0], 'total_calls': hits[0] + misses[0], 'current_size': len(cached_func.storage._cache) } wrapper.cache_info = cache_info return wrapper # 使用方式:先装饰ring.lru,再用我们的跟踪器 class MyClass: @track_cache_stats @ring.lru() @staticmethod def get_hostname_by_id(object_id): return Monkey.get_single_monkey_by_id(object_id).hostname # 调用统计 stats = MyClass.get_hostname_by_id.cache_info() print "Cache stats: {}".format(stats)
这个方法完全不依赖ring的内部私有属性,通过_get_key生成缓存键,再用storage.exists判断是否命中,兼容性更好。
内容的提问来源于stack exchange,提问作者Shay Nehmad
相关产品推荐
相关产品推荐

