python自带缓存lru_cache用法及扩展的使用_python

目录, 2. 关于.wrap装饰器产生的影响, 3. 说说自制简易的.缓存同redis缓存之间的区别, 5. 进行总结。

要详细讲述缓存方法是怎样达成的, 需与官方文档以及源码相结合, 它跟redis缓存所存在的区别是什么, 在使用期间碰到.wrap装饰器时会出现怎样的改变, 还要知晓它给我们予以了哪些功能, 之后在这个基础之上实现我们自己制作的缓存方法, 本篇博客就要述及这些内容。

  1. 的使用

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("新增用户成功")
  1. .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装饰器前后的变化

未完待续。。。。。。。。。

  1. 自制简易的

3.1 提供的功能

缓存装饰器提供的功能有:

可以知道, 从所列出的功能来讲, 自带的缓存方法能够满足我们在日常工作里的大部分需求, 如果是这样的话, 只不过它不包含一项较为重要的特性, 也就是超时自动去删除缓存结果这方面, 因此在我们自己制作的当中, 我们会去实现缓存的超时过期这项功能。

3.2 cache的核心部件

在作用域内存在一个相对全局的字典变量cache={}

设置处于作用域之内的、相对全局而言的变量, 其中涵盖命中次数 hits, 有着未命中次数, 存在最大缓存数量, 还有当前缓存大小。

第二点中的缓存信息中增加缓存加入时间和缓存有效时间

3.3 的实现

待实现。。。。。。。。。。。。

  1. 缓存和redis缓存的区别

比较类型

缓存类型

缓存在app进程内存中

缓存在redis管理的内存中

分布式

只缓存在单个app进程中

可做分布式缓存

数据类型

hash 参数作为key,返回结果为value

有5种类型的数据结构

适用场景

比较小型的系统、单体应用

常用的缓存解决方案

功能

缓存功能但是缺少过期时间控制,但是使用上更加便捷

具备缓存需要的各种要素

  1. 总结

纵观上述情况, 自带的缓存功能乃应用于相对较为小型的单体应用中。其优势在于能够极为便利地依据传入各类不同参数来缓存相应结果, 而且能够切实有效地把控缓存结果数量, 当超出所设数量之际, 依据LRU算法淘汰命中次数最少的缓存结果。其不足在于没办法去设置缓存过期时间。

相关推荐
招财小梗1 小时前
沈阳AI企业咨询可定制数字化方案吗?
大数据·人工智能·python
leihefeng1 小时前
邮件文本分类:CountVectorizer / TF-IDF + 朴素贝叶斯
python·分类·数据挖掘·tf-idf·sklearn
码艺-Alimjan1 小时前
维吾尔语数字转文本
java·javascript·python·算法·go
天空属于哈夫克31 小时前
企业微信 API 自动发送消息:从流程到实战
python·自动化·企业微信
SunnyDays10112 小时前
如何使用 Python 给 PDF 添加附件:文档附件与附件注释
开发语言·python·pdf
步行cgn2 小时前
@Value 详解:Spring 属性注入的核心注解
java·python·spring
SamChan902 小时前
PDF翻译服务端到端基准测试:4款主流方案的吞吐量、延迟、内存占用对比
服务器·网络·python·ai·pdf·wpf
2501_937860942 小时前
Java 文件操作与IO(下):字节流、字符流实战IO读写
java·开发语言·python
xixingzhe22 小时前
SpringBoot 接口缓存实现
spring boot·后端·缓存