目录, 2. 关于.wrap装饰器产生的影响, 3. 说说自制简易的.缓存同redis缓存之间的区别, 5. 进行总结。
要详细讲述缓存方法是怎样达成的, 需与官方文档以及源码相结合, 它跟redis缓存所存在的区别是什么, 在使用期间碰到.wrap装饰器时会出现怎样的改变, 还要知晓它给我们予以了哪些功能, 之后在这个基础之上实现我们自己制作的缓存方法, 本篇博客就要述及这些内容。
- 的使用
1.1 参数详解
下面是方法那儿的实行做出来的情况, 我们瞅见, 能够供我们传进去的参数存在两个以及typed, 倘使不进行传递的话, 那么其所具备的默认值是128, typed的默认值是False。里边的参数所代表的, 是经过装饰的方法能够缓存的最大结果数量, 要是其值为默认的128, 这就意味着被装饰的方法最多能够缓存128个返回的结果, 要是传入的值是None, 那就表明可以缓存无穷多个结果 , 你也许会好奇经过装饰的那方法的n 个结果是如何出现的 , 举个例子 , 被装饰的方法设的是def add(a, b): , 当这个函数被装饰好之后 , 我们调用add(1, 2)以及add(3 ,4) ,就会缓存不一样的结果。倘若typed被设置成true , 不同类型的函数参数会被分开来缓存。比如说, f(3), 还有f(3.0), 会被当作有差异的, 然后分别进行缓存处理。
brush:py;
def lru_cache(maxsize=128, typed=False):
if isinstance(maxsize, int):
if maxsize < 0:
maxsize = 0
elif maxsize is not None:
raise TypeError('Expected maxsize to be an integer or None')
def decorating_function(user_function):
wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)
return update_wrapper(wrapper, user_function)
return decorating_function
1.2 基本用法
我们编写接口之际, 或许 需要缓存某些变动不太显著的数据, 像配置信息之类的, 我们有可能编写下面这样的接口:
brush:py;
@api.route("/user/info", methods=["GET"])
@functools.lru_cache()
@login_require
def get_userinfo_list():
userinfos = UserInfo.query.all()
userinfo_list = [user.to_dict() for user in userinfos]
return jsonify(userinfo_list)
我们对从数据库那儿查询得来的用户信息进行了缓存, 下次再度调用此接口之际, 将会直接把用户信息列表予以返回, 而并非是再次去执行一遍数据库查询背后隐藏的逻辑, 如此这般能够在效果上有效地减少IO的次数, 进而加快接口的反应速度。
1.3 进阶用法
还是以上面那个例子来说, 倘若出现用户删除或者新增的状况, 当我们再度请求用户接口时, 所返还的依旧是缓存里的数据, 如此一来, 所返回的这些信息和我们数据库当中的数据便会存有差异, 所以, 一旦发生用户新增或者删除行为时, 我们就得清除原先的缓存, 之后再去请求用户接口便能够重新加载缓存。
brush:py;
@api.route("/user/info", methods=["POST"])
@functools.lru_cache()
@login_require
def add_user():
user = UserInfo(name="李四")
db.session.add(user)
db.session.commit()
# 清除get_userinfo_list中的缓存
get_userinfo_list = current_app.view_functions["api.get_machine_list"]
cache_info = get_userinfo_list.cache_info()
# cache_info 具名元组,包含命中次数 hits,未命中次数 misses ,最大缓存数量 maxsize 和 当前缓存大小 currsize
# 如果缓存数量大于0则清除缓存
if cache_info[3] > 0:
get_userinfo_list.cache_clear()
return jsonify("新增用户成功")
在上面这个用法里, 我们, 要是我们将装饰器与装饰器把位置进行调换的话, 上述的那种写法将会出现报错, 这是由于装饰器之中运用了.wrap模块来开展装饰所造成的, 具体原因我会在下节予以解释, 要是想不报错得改成如下这种写法。
brush:py;
@api.route("/user/info", methods=["POST"])
@login_require
@functools.lru_cache()
def add_user():
user = UserInfo(name="李四")
db.session.add(user)
db.session.commit()
# 清除get_userinfo_list中的缓存
get_userinfo_list = current_app.view_functions["api.get_machine_list"]
cache_info = get_userinfo_list.__wrapped__.cache_info()
# cache_info 具名元组,包含命中次数 hits,未命中次数 misses ,最大缓存数量 maxsize 和 当前缓存大小 currsize
# 如果缓存数量大于0则清除缓存
if cache_info[3] > 0:
get_userinfo_list.__wrapped__.cache_clear()
return jsonify("新增用户成功")
- .wrap装饰器对的影响
于上节时我们见到, 鉴于@以及@.()装饰器的顺序存有差异, 故而致使程序出现是否报错的情况, 其中主要涵盖两点:
当我们了解完这两点后就可以理解上述写法了。
2.1 多个装饰器装饰同一函数时的执行顺序
这里从其他地方盗了一段代码来解释一下,如下:
brush:py;
def decorator_a(func):
print('Get in decorator_a')
def inner_a(*args,**kwargs):
print('Get in inner_a')
res = func(*args,**kwargs)
return res
return inner_a
def decorator_b(func):
print('Get in decorator_b')
def inner_b(*args,**kwargs):
print('Get in inner_b')
res = func(*args,**kwargs)
return res
return inner_b
@decorator_b
@decorator_a
def f(x):
print('Get in f')
return x * 2
f(1)
输出结果如下:
'Get in '
'Get in '
'Get in '
'Get in '
'Get in f'
是不是很像中的中间件的执行顺序,其实原理都差不多。
2.2 .wrap原理
引用其他博主的描述:
装饰器在进行实现之际,被装饰之后的那个函数实际上已然成为另外的一个函数了, 函数名以及等诸多函数属性会出现改变, 鉴于此为了不造成影响, 在有的包当中提供了一个被称作wraps的东西来消除如此这般的副作用, 当去写一个的时候, 最好是在实现之前添加的wrap, 它能够留存原有函数的名称以及。
添加补充内容, 该函数会设置一个属性, 这个属性用来指向原函数, 目的是为了能够对原函数进行访问, 如此一来, 便能够对上文中1.3节内我们所采用的写法做出解释了。

2.3 使用wrap装饰器前后的变化
未完待续。。。。。。。。。
- 自制简易的
3.1 提供的功能
缓存装饰器提供的功能有:
可以知道, 从所列出的功能来讲, 自带的缓存方法能够满足我们在日常工作里的大部分需求, 如果是这样的话, 只不过它不包含一项较为重要的特性, 也就是超时自动去删除缓存结果这方面, 因此在我们自己制作的当中, 我们会去实现缓存的超时过期这项功能。
3.2 cache的核心部件
在作用域内存在一个相对全局的字典变量cache={}
设置处于作用域之内的、相对全局而言的变量, 其中涵盖命中次数 hits, 有着未命中次数, 存在最大缓存数量, 还有当前缓存大小。
第二点中的缓存信息中增加缓存加入时间和缓存有效时间
3.3 的实现
待实现。。。。。。。。。。。。
- 缓存和redis缓存的区别
比较类型
缓存类型
缓存在app进程内存中
缓存在redis管理的内存中
分布式
只缓存在单个app进程中
可做分布式缓存
数据类型
hash 参数作为key,返回结果为value
有5种类型的数据结构
适用场景
比较小型的系统、单体应用
常用的缓存解决方案
功能
缓存功能但是缺少过期时间控制,但是使用上更加便捷
具备缓存需要的各种要素
- 总结
纵观上述情况, 自带的缓存功能乃应用于相对较为小型的单体应用中。其优势在于能够极为便利地依据传入各类不同参数来缓存相应结果, 而且能够切实有效地把控缓存结果数量, 当超出所设数量之际, 依据LRU算法淘汰命中次数最少的缓存结果。其不足在于没办法去设置缓存过期时间。