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中bisect模块用法实例

    python中bisect模块用法实例

    这篇文章主要介绍了python中bisect模块用法实例,以实例形式介绍了bisect模块中几种常见函数的用法,非常具有实用价值,需要的朋友可以参考下
    2014-09-09
  • python logging 重复写日志问题解决办法详解

    python logging 重复写日志问题解决办法详解

    这篇文章主要介绍了python logging 重复写日志问题解决办法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • Python Socket编程实现猜数字游戏交互体验

    Python Socket编程实现猜数字游戏交互体验

    当利用Python的Socket编程创建一个猜数字游戏时,需要分别实现服务器端和客户端的逻辑,本文将详细描述这两个部分的功能和代码片段
    2024-01-01
  • django数据库报错解决汇总:django.db.utils.OperationalError 1045,1049,2003

    django数据库报错解决汇总:django.db.utils.OperationalError 1045,1049,

    这篇文章主要给大家介绍了关于django数据库报错解决:django.db.utils.OperationalError 1045,1049,2003的相关资料,文中将解决的办法介绍的非常详细,需要的朋友可以参考下
    2023-02-02
  • django多个APP的urls设置方法(views重复问题解决)

    django多个APP的urls设置方法(views重复问题解决)

    今天小编就为大家分享一篇django多个APP的urls设置方法(views重复问题解决),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • Python基于pygame实现单机版五子棋对战

    Python基于pygame实现单机版五子棋对战

    这篇文章主要为大家详细介绍了Python基于pygame实现单机版五子棋对战,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • PyCharm连接远程服务器的超级详细教程

    PyCharm连接远程服务器的超级详细教程

    Pycharm可以与服务器建立连接,把相应的项目同步到服务器上,下面这篇文章主要给大家介绍了关于PyCharm连接远程服务器的超级详细教程,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • Anaconda如何查看自己目前安装的包详解

    Anaconda如何查看自己目前安装的包详解

    Anaconda是一种用于数据科学和机器学习的开源发行版,它包含了很多常用的Python包和工具,如NumPy、Pandas、Scipy、Scikit-Learn等,下面这篇文章主要给大家介绍了关于Anaconda如何查看自己目前安装的包的相关资料,需要的朋友可以参考下
    2023-05-05
  • 11个并不被常用但对开发非常有帮助的Python库

    11个并不被常用但对开发非常有帮助的Python库

    这篇文章主要介绍了11个并不被常用但对开发非常有帮助的Python库,这些库大都被放在Github上开源、并且经过一段时间的编写和维护,对Python开发有一定的帮助,需要的朋友可以参考下
    2015-03-03
  • 跟老齐学Python之有容乃大的list(3)

    跟老齐学Python之有容乃大的list(3)

    现在是讲lis的第三章了。俗话说,事不过三,不知道在开头,我也不知道这一讲是不是能够把基础的list知识讲完呢。哈哈。其实如果真正写文章,会在写完之后把这句话删掉的。而我则是完全像跟看官聊天一样,就不删除了。
    2014-09-09

最新评论