Python中缓存lru_cache的基本介绍和讲解

 更新时间:2022年01月28日 10:34:23   作者:曲鸟  
缓存是一种将定量数据加以保存以备迎合后续请求的处理方式,旨在加快数据的检索速度,下面这篇文章主要给大家介绍了关于Python中缓存lru_cache的基本介绍和讲解的相关资料,需要的朋友可以参考下

一、前言

我们经常谈论的缓存一词,更多的类似于将硬盘中的数据存放到内存中以至于提高读取速度,比如常说的redis,就经常用来做数据的缓存。
Python的缓存(lru_cache)是一种装饰在被执行的函数上,将其执行的结果缓存起来,当下次请求的时候,如果请求该函数的传参未变则直接返回缓存起来的结果而不再执行函数的一种缓存装饰器。

那它和redis的区别在哪?有什么优势?怎么使用? 下面为你讲解

二、举例说明

1.现在我们先不使用缓存来写一个求两数之和的函数,并调用执行它两次:

def test(a, b):
    print('开始计算a+b的值...')
    return a + b


print('1+2等于:', test(1, 2))
print('1+2等于:', test(1, 2))

执行结果

开始计算a+b的值...
1+2等于: 3
开始计算a+b的值...
1+2等于: 3

可以看到test被执行了两次,现在我们加上缓存再进行执行:

from functools import lru_cache

@lru_cache
def test(a, b):
    print('开始计算a+b的值...')
    return a + b

print(test(1, 2))
print(test(1, 2))

执行结果

开始计算a+b的值...
1+2等于: 3
1+2等于: 3

可以看到test函数只被执行了一次,第二次的调用直接输出了结果,使用了缓存起来的值。

2.当我们使用递归求斐波拉契数列 (斐波那契数列指的是这样一个数列:0,1,1,2,3,5,8,它从第3项开始,每一项都等于前两项之和) 的时候,缓存对性能的提升就尤其明显了:

不使用缓存求第40项的斐波拉契数列

import datetime

def fibonacci(num):
	# 不使用缓存时,会重复执行函数
    return num if num < 2 else fibonacci(num - 1) + fibonacci(num - 2)

start = datetime.datetime.now()
print(fibonacci(40))
end = datetime.datetime.now()
print('执行时间', end - start)

执行时间

执行时间 0:00:29.004424

使用缓存求第40项的斐波拉契数列:

import datetime

def fibonacci(num):
	# 不使用缓存时,会重复执行函数
    return num if num < 2 else fibonacci(num - 1) + fibonacci(num - 2)

start = datetime.datetime.now()
print(fibonacci(40))
end = datetime.datetime.now()
print('执行时间', end - start)

执行时间

执行时间 0:00:00

两个差距是非常明显的,因为不使用缓存时,相当于要重复执行了很多的函数,而使用了lru_cache则把之前执行的函数结果已经缓存了起来,就不需要再次执行了。

三、lru_cache 用法

1.参数详解

查看lru_cache源码会发现它可以传递两个参数:maxsize、typed:

def lru_cache(maxsize=128, typed=False):
    """Least-recently-used cache decorator.

    If *maxsize* is set to None, the LRU features are disabled and the cache
    can grow without bound.
	...
	"""

1) maxsize

代表被lru_cache装饰的方法最大可缓存的结果数量 (被装饰方法传参不同一样,则结果不一样;如果传参一样则为同一个结果), 如果不指定传参则默认值为128,表示最多缓存128个返回结果,当达到了128个时,有新的结果要保存时,则会删除最旧的那个结果。如果maxsize传入为None则表示可以缓存无限个结果;

2)typed

默认为false,代表不区分数据类型,如果设置为True,则会区分传参类型进行缓存,官方是这样描述的:

如果typed为True,则将分别缓存不同类型的参数,
例如,f(3.0)和f(3)将被视为具有明显的结果。

但在python3.9.8版本下进行测试,typed为false时,按照官方的测试方法测试得到的还是会被当成不同的结果处理,这个时候typed为false还是为true都会区别缓存,这与官方文档的描述存在差异:

from functools import lru_cache

@lru_cache
def test(a):
    print('函数被调用了...')
    return a

print(test(1.0))
print(test(1))

执行结果

函数被调用了...
1.0
函数被调用了...

但如果是多参数的情况下,则会被当成一个结果:

from functools import lru_cache

@lru_cache
def test(a, b):
    print('函数被调用了...')
    return a , b

print(test(1.0, 2.0))
print(test(1, 2))

执行结果

函数被调用了...
(1.0, 2.0)
(1.0, 2.0)

这个时候设置typed为true时,则会区别缓存:

from functools import lru_cache

@lru_cache(typed=True)
def test(a, b):
    print('函数被调用了...')
    return a , b

print(test(1.0, 2.0))
print(test(1, 2))

执行结果

函数被调用了...
(1.0, 2.0)
函数被调用了...
(1, 2)

当传参个数大于1时,才符合官方的说法,不清楚是不是官方举例有误

2. lru_cache不支持可变参数

当传递的参数是dict、list等的可变参数时,lru_cache是不支持的,会报错:

from functools import lru_cache

@lru_cache
def test(a):
    print('函数被执行了...')
    return a

print(test({'a':1}))

报错结果

TypeError: unhashable type: 'dict'

四、lru_cache 与redis的区别

缓存缓存位置是否支持可变参数是否支持分布式是否支持过期时间设置支持的数据结构需单独安装
redis缓存在redis管理的内存中支持5种数据结构
lru_cache缓存在应用进程的内存中,应用被关闭则被清空字典(参数为:key,结果为:value)

五、总结

经过上面的分析,lru_cache 功能相对于redis来说要简单许多,但使用起来更加方便,适用于小型的单体应用。如果涉及的缓存的数据种类比较多并且想更好的管理缓存、或者需要缓存数据有过期时间(类似登录验证的token)等,使用redis是优于lru_cache的。

到此这篇关于Python中缓存lru_cache的基本介绍和讲解的文章就介绍到这了,更多相关Python中缓存lru_cache内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python 动态规划问题解析(背包问题和最长公共子串)

    python 动态规划问题解析(背包问题和最长公共子串)

    这篇文章主要介绍了python 动态规划(背包问题和最长公共子串),在动态规划中,你要将某个指标最大化。在这个例子中,你要找出两个单词的最长公共子串。fish和fosh都包含的最长子串是什么呢,感兴趣的朋友跟随小编一起看看吧
    2022-05-05
  • Python实现字典序列ChainMap

    Python实现字典序列ChainMap

    容器数据类型包括数组list,字典dict以及元组tuple等。本篇主要介绍了ChainMap字典序列的使用,需要的朋友们下面随着小编来一起学习学习吧
    2021-06-06
  • python数字图像处理skimage读取显示与保存图片

    python数字图像处理skimage读取显示与保存图片

    这篇文章主要为大家介绍了python数字图像处理使用skimage读取显示与保存图片示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Python增强赋值和共享引用注意事项小结

    Python增强赋值和共享引用注意事项小结

    这篇文章主要给大家介绍了关于Python增强赋值和共享引用注意事项的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Python具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-05-05
  • Python操作MySQL MongoDB Oracle三大数据库深入对比

    Python操作MySQL MongoDB Oracle三大数据库深入对比

    对于数据分析师来说,学习数据库最重要的就是学习它们的查询功能。这篇文章就以这个为切入点,为大家讲述如何用Python操作这3个数据库
    2021-10-10
  • python的pygal模块绘制反正切函数图像方法

    python的pygal模块绘制反正切函数图像方法

    在本篇文章中我们给大家整理了关于如何用python的pygal模块绘制反正切函数图像的知识点内容,有需要的朋友们可以学习下。
    2019-07-07
  • Python趣味爬虫之爬取爱奇艺热门电影

    Python趣味爬虫之爬取爱奇艺热门电影

    好久没带大家实现Python爬虫了,文中有非常详细的代码示例,对不会爬虫的小伙伴们很有帮助哦,需要的朋友可以参考下
    2021-06-06
  • python畅玩os模块以及顺便批量修改图片尺寸

    python畅玩os模块以及顺便批量修改图片尺寸

    这篇文章主要介绍了python畅玩os模块以及顺便批量修改图片尺寸方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Selenium 安装和简单使用的实现

    Selenium 安装和简单使用的实现

    这篇文章主要介绍了Selenium 安装和简单使用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • python连接并简单操作SQL server数据库详细步骤

    python连接并简单操作SQL server数据库详细步骤

    python作为一门十分火热的编程语言,操作数据库自然是必不可少的,下面这篇文章主要给大家介绍了关于python连接并简单操作SQL server数据库的相关资料,需要的朋友可以参考下
    2023-06-06

最新评论