cacheutils
-缓存和缓存¶
cacheutils
包含基本缓存类型的一致实现。目前有两种可供选择:
两个缓存都是 dict
子类型,设计为尽可能可互换,以便于实验。使用缓存增强性能的一个关键实践是确保缓存策略有效。如果缓存不断丢失,只会增加更多的开销和代码复杂性。标准统计数据为:
hit_count
-查询键在缓存中的次数
miss_count
-关键字不存在和/或被缓存提取的次数
soft_miss_count
-没有密钥,但调用者提供了默认密钥的次数,如dict.get()
和dict.setdefault()
。软未命中是未命中的子集,因此该数字始终小于或等于miss_count
。
另外, cacheutils
提供 ThresholdCounter
,这是一个类似缓存的绑定计数器,可用于在线统计信息收集。
了解更多有关 caching algorithms on Wikipedia 。
最近最少插入(LRI)¶
这个 LRI
是一种更简单的缓存,它实现了一种非常简单的先进先出(FIFO)方法来清除缓存。如果用例需要简单、开销非常低的缓存,例如开销较高的本地操作(例如,字符串操作),那么LRI可能是正确的选择。
- class boltons.cacheutils.LRI(max_size=128, values=None, on_miss=None)[源代码]¶
这个
LRI
实现基本的 Least Recently Inserted 从战略到缓存。人们也可以认为这是一种SizeLimitedDefaultDict
。on_miss 是接受缺失密钥的可调用对象(与
collections.defaultdict
的“DEFAULT_FACTORY”,它不接受任何参数。)还要注意,与LRI
vt.的.LRI
配备了统计信息跟踪工具。>>> cap_cache = LRI(max_size=2) >>> cap_cache['a'], cap_cache['b'] = 'A', 'B' >>> from pprint import pprint as pp >>> pp(dict(cap_cache)) {'a': 'A', 'b': 'B'} >>> [cap_cache['b'] for i in range(3)][0] 'B' >>> cap_cache['c'] = 'C' >>> print(cap_cache.get('a')) None >>> cap_cache.hit_count, cap_cache.miss_count, cap_cache.soft_miss_count (3, 1, 1)
最近最少使用(LRU)¶
这个 LRU
是更高级的缓存,但它仍然非常简单。当它达到容量时,新的插入项将替换最近最少使用的项。对于各种应用程序,此策略使LRU成为比LRI更有效的缓存,但也需要对其所有API执行更多操作,尤其是读取。不像 LRI
,LRU内置了螺纹安全。
- class boltons.cacheutils.LRU(max_size=128, values=None, on_miss=None)[源代码]¶
这个
LRU
是dict
的子类型实现 Least-Recently Used 缓存策略。- 参数:
max_size (int) -- 要缓存的最大项目数。默认为
128
。values (iterable) -- 缓存的初始值。默认为
None
。on_miss (callable) -- 接受单个参数(缓存中不存在的键)并返回要缓存的值的可调用对象。
>>> cap_cache = LRU(max_size=2) >>> cap_cache['a'], cap_cache['b'] = 'A', 'B' >>> from pprint import pprint as pp >>> pp(dict(cap_cache)) {'a': 'A', 'b': 'B'} >>> [cap_cache['b'] for i in range(3)][0] 'B' >>> cap_cache['c'] = 'C' >>> print(cap_cache.get('a')) None
该缓存还配备了统计信息收集工具。
hit_count
,miss_count
,及soft_miss_count
都是可用于自省缓存性能的整数成员。(“软”未命中是指未引起KeyError
,例如,LRU.get()
或on_miss
用于缓存默认设置。>>> cap_cache.hit_count, cap_cache.miss_count, cap_cache.soft_miss_count (3, 1, 1)
除了大小限制的高速缓存行为和统计之外,
LRU
与其父类(内置的Python)类似dict
。
自动函数缓存¶
继续高速缓存可调整性和实验的主题, cacheutils
还提供了一种可插入的方法来缓存函数返回值: cached()
函数装饰符和 cachedmethod()
方法修饰器。
- boltons.cacheutils.cached(cache, scoped=True, typed=False, key=None)[源代码]¶
使用您选择的缓存对象缓存任何函数。请注意,包装的函数应该只接受 hashable 争论。
- 参数:
>>> my_cache = LRU() >>> @cached(my_cache) ... def cached_lower(x): ... return x.lower() ... >>> cached_lower("CaChInG's FuN AgAiN!") "caching's fun again!" >>> len(my_cache) 1
- boltons.cacheutils.cachedmethod(cache, scoped=True, typed=False, key=None)[源代码]¶
类似于
cached()
,cachedmethod
用于根据方法的参数缓存方法,使用dict
-喜欢 cache 对象。- 参数:
cache (str/Mapping/callable) -- 可以是实例上属性的名称,可以是任何映射/:类:类似于`DICTION`的对象,也可以是返回映射的Callable。
scoped (bool) -- 方法本身及其绑定到的对象是否为缓存键的一部分。
True
默认情况下,不同的方法不会读取彼此的缓存结果。False
对于某些共享缓存使用情形非常有用。更高级的行为可以通过 key 争论。typed (bool) -- 是否将参数类型作为缓存检查的因素。默认
False
,设置为True
导致的缓存键3
和3.0
被认为不平等。key (callable) -- 具有匹配签名的可调用对象
make_cache_key()
它返回要用作缓存中的键的Hasable值的元组。
>>> class Lowerer(object): ... def __init__(self): ... self.cache = LRI() ... ... @cachedmethod('cache') ... def lower(self, text): ... return text.lower() ... >>> lowerer = Lowerer() >>> lowerer.lower('WOW WHO COULD GUESS CACHING COULD BE SO NEAT') 'wow who could guess caching could be so neat' >>> len(lowerer.cache) 1
类似的功能可以在Python3.4中找到 functools.lru_cache()
修饰器,但函数工具方法不支持相同的缓存策略修改,也不支持跨多个函数共享缓存对象。
阈值有界计数¶
- class boltons.cacheutils.ThresholdCounter(threshold=0.001)[源代码]¶
A bounded 从关键字到计数的类似字典的映射。ThresholdCounter在以下时间间隔(1/ threshold )添加,维护其计数至少表示 threshold 总数据的比率。换句话说,如果ThresholdCounter中不存在特定的键,则其计数小于 threshold 在全部数据中。
>>> tc = ThresholdCounter(threshold=0.1) >>> tc.add(1) >>> tc.items() [(1, 1)] >>> tc.update([2] * 10) >>> tc.get(1) 0 >>> tc.add(5) >>> 5 in tc True >>> len(list(tc.elements())) 11
正如您在上面看到的,该API保持与
collections.Counter
。最显著的功能遗漏是,不能直接设置、不计算或删除已计算的项,因为这会扰乱计算。当您需要动态键控数据的尽力而为的长期计数时,请使用ThresholdCounter。如果没有像这样的受限数据结构,动态键通常表示内存泄漏,并可能影响应用程序的可靠性。ThresholdCounter的项替换策略是完全确定的,可以被认为是 Amortized Least Relevant 。它将存储的密钥的绝对上限为 (2/threshold) ,但实际上 (1/threshold) 对于均匀随机的数据流,预计要高出一个或两个数量级,而对于真实世界的数据,则要高出一个或两个数量级。
该算法是Manku&Motwani在《数据流上的近似频率计数》中描述的有损计数算法的实现。向库尔特·罗斯致敬,感谢他的发现和初步实施。