前言
flask-cache的版本为:0.13.1。具体的使用例程见官方网站
flask-cache主要实现了两种功能,一种是对模板的缓存,一种是对视图函/其他函数的缓存。其中对模板缓存的原理分析请戳这里。下边我们主要写对函数的缓存原理。
源码之旅
flask-cache 对函数的缓存有两种方式,通俗的讲可以分为:
记忆参数型缓存:由@cached装饰器实现
无记忆参数型缓存:由@memoize装饰器实现
源码结构解读
flask-cache 是利用werkzeug提供的缓存函数实现的。
其中对缓存的存储是由werkzeug.contrib.cache.py文件实现的。
1)cache.py结构图
由上图可以看出,这里主要实现了SimpleCache,redis,memcached等缓存的配置功能。其中类BaseCache是其他缓存的基类,定义了缓存操作的接口操作。其方法图如下:
下边我们看一下cache.py中自己实现的一个简单的cache,SimpleCache
2)SimpleCache 实现原理
SimpleCache 是一个简单的内存缓存,只能用于单进程的环境,不能保证线程的安全性。而且也没有实现数据的持久化操作。其缓存的失效机制是由两个参数控制:threshold 与default_timeout。
基本原理是:当缓存中的key的个数超过阈值threshold ,删除生命周期大于default_timeout的key。如果default_timeout =0 表示永远不超期。
def __init__(self, threshold=500, default_timeout=300):
BaseCache.__init__(self, default_timeout)
self._cache = {}
self.clear = self._cache.clear
self._threshold = threshold
上边是初始化方法,默认的缓存key的容量是500,默认超期时间是300s.
初始化时,首先初始化基类BaseCache,然后创建了一个字典self._cache用于存储缓存数据。
def _prune(self):
if len(self._cache) > self._threshold: # 当前缓存的key的个数超过阈值
now = time()
toremove = []
for idx, (key, (expires, _)) in enumerate(self._cache.items()):
# 查找的生命周期已经超时的key
if (expires != 0 and expires <= now) or idx % 3 == 0:
toremove.append(key)
for key in toremove:
self._cache.pop(key, None)
_prune 方法实现超期检测功能,每当进行set缓存操作时,会首先调用_prune 来校验剔除超期的元素。
def set(self, key, value, timeout=None):
expires = self._normalize_timeout(timeout)
self._prune()
self._cache[key] = (expires, pickle.dumps(value,
pickle.HIGHEST_PROTOCOL))
return True
set函数是缓存的核心函数,其流程是首先计算期望的超期时间,然后调用_prune函数 检查校验操起元素。讲要缓存的元素放入内存的字典中,注意,这里字典的值不是直接存储数据的值,而是将数据的value进行序列化之后与expires组成元组作为key的value放入字典中。序列化的目的是为了方便对象的存储和网络传输。
get函数负责中缓存中取值,实现很简单,就是从字典中取值,然后判断是否超期,如果超期返回None
3)对函数缓存的具体实现
首先看一下flask-cache包的结构图:
init.py文件实现核心的功能:函数的缓存功能
_compat.py文件是python2与3的兼容转换
backends.py 文件是与werk