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

目录
  • 一、前言
  • 二、举例说明
  • 三、lru_cache 用法
    • 1.参数详解
    • 2. lru_cache不支持可变参数
  • 四、lru_cache 与redis的区别
  • 五、总结

一、前言

我们经常谈论的缓存一词,更多的类似于将硬盘中的数据存放到内存中以至于提高读取速度,比如常说的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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python 的lru_cache装饰器使用简介

    Python 的 lru_cache 装饰器是一个为自定义函数提供缓存功能的装饰器.其内部会在下次以相同参数调用该自定义函数时直接返回计算好的结果.通过缓存计算结果可以很好地提升性能. 1 从示例说起 假设我们有一个计算斐波那契数列的求和函数,其内部采用递归方式实现. from xxx.clock_decorator import clock @clock def fibonacci(n): if n<2: return n return fibonacci(n-2)+fibonacci(n-1

  • Python中lru_cache的使用和实现详解

    在计算机软件领域,缓存(Cache)指的是将部分数据存储在内存中,以便下次能够更快地访问这些数据,这也是一个典型的用空间换时间的例子.一般用于缓存的内存空间是固定的,当有更多的数据需要缓存的时候,需要将已缓存的部分数据清除后再将新的缓存数据放进去.需要清除哪些数据,就涉及到了缓存置换的策略,LRU(Least Recently Used,最近最少使用)是很常见的一个,也是 Python 中提供的缓存置换策略. 下面我们通过一个简单的示例来看 Python 中的 lru_cache 是如何使用的.

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

    目录 1. lru_cache的使用 1.1 参数详解 1.2 基本用法 1.3 进阶用法 2. functiontools.wrap装饰器对lru_cache的影响 2.1 多个装饰器装饰同一函数时的执行顺序 2.2 functiontools.wrap原理 2.3 使用wrap装饰器前后的变化 3. 自制简易的my_cache 3.1 lru_cache提供的功能 3.2 cache的核心部件 3.3 my_cache的实现 4. lru_cache缓存和redis缓存的区别 5. 总结 本

  • Python实现的一个简单LRU cache

    起因:我的同事需要一个固定大小的cache,如果记录在cache中,直接从cache中读取,否则从数据库中读取.python的dict 是一个非常简单的cache,但是由于数据量很大,内存很可能增长的过大,因此需要限定记录数,并用LRU算法丢弃旧记录.key 是整型,value是10KB左右的python对象 分析: 1)可以想到,在对于cache,我们需要维护 key -> value 的关系 2)而为了实现LRU,我们又需要一个基于时间的优先级队列,来维护   timestamp  ->

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

    目录 一.前言 二.举例说明 三.lru_cache 用法 1.参数详解 2. lru_cache不支持可变参数 四.lru_cache 与redis的区别 五.总结 一.前言 我们经常谈论的缓存一词,更多的类似于将硬盘中的数据存放到内存中以至于提高读取速度,比如常说的redis,就经常用来做数据的缓存.Python的缓存(lru_cache)是一种装饰在被执行的函数上,将其执行的结果缓存起来,当下次请求的时候,如果请求该函数的传参未变则直接返回缓存起来的结果而不再执行函数的一种缓存装饰器. 那

  • Python中的引用与copy介绍

    目录 Python中的引用和copy 1.引用整型数据及列表 2.传递引用 3.copy模块中的copy()和deepcopy() Python中的引用和copy 1.引用整型数据及列表 这里以整型数据类型及列表为例 对于赋值字符串.整型.元组等不可更改数据的变量,其保存的仅是值,改变新变量中的值并不会影响原来变量中的值 origin = 1 new = origin print("new = ",new) new = 2 print("origin = ",ori

  • Python中最神秘missing()函数介绍

    目录 前言 1.有点价值的missing() 2.神出鬼没的missing() 3.被施魔法的missing() 4.小结 前言 一个非常神秘的魔术方法. 这个方法非常不起眼,用途狭窄,我几乎从未注意过它,然而,当发现它可能是上述"定律"的唯一例外情况时,我认为值得再写一篇文章来详细审视一下它. 本文主要关注的问题有: (1) missing()到底是何方神圣? (2) missing()有什么特别之处?擅长"大变活人"魔术? (3) missing()是否真的是上

  • Python中线程锁的使用介绍

    目录 前言 方式一:使用try/finally,确保锁肯定会被释放. 方式二:with语句避免使用try/finally. 总结 前言 当有多个线程,且它们同时访问同一资源时,需要考虑如何避免线程冲突.解决办法是使用线程锁.锁由Python的threading模块提供,并且它最多被一个线程所持有.当一个线程试图获取一个已经锁在资源上的锁时,该线程通常会暂停运行,直到这个锁被释放.看看下面的不具备锁功能的例子: #!/usr/bin/env python3 # -*- coding:utf-8 -

  • Python中安装库的常用方法介绍

    目录 方法一:需要在网络条件下安装 方法二:离线安装 方法三:换源安装 总结 方法一:需要在网络条件下安装 win+R进入运行框输入命令cmd 点击确定进入 普通下载:pip install 模块名字 例如:输入 pip install pygame pip install numpy pip install xlwt xlwt代表需要安装所需包和库等 列出安装版本:pip list 和pip freeze 卸载模块: pip uninstall xlwt Y--确定卸载,n--否 指定版本下载

  • Python中python-nmap模块的使用介绍

    目录 一.python-nmap的安装 二.python-nmap模块的使用 1.portScanner()类 环境: python 2.7.13 Windows和Linux默认都是不安装python-nmap的,我们得手动安装 一.python-nmap的安装 linux: wge t http://xael.org/pages/python-nmap-0.6.1.tar.gz tar  -zxvf  python-nmap-0.6.1.tar.gz cd  python-nmap-0.6.1

  • Python中字典的相关操作介绍

    字典的添加与修改 # coding:utf-8 if __name__ == '__main__': example = {'name': 'xie', 'age': 27} example2 = example.copy() example3 = example.copy() ''' 例1:使用dict[key] = value,这种方法如果dict中存在该key,则修改该key上的值=value,不存在该key,则创建该key=>value 例2:使用dict.setdefault(key,

  • python中lower函数实现方法及用法讲解

    之前小编介绍过python中将字符串小写字符转为大写的upper函数的使用方法(upper函数).有将小写转为大写的需要,那也有将大写转为小写的情况.本文主要介绍在python中可以将字符串大写自摸转换为小写字母的lower函数. 1.lower() 转换字符串中所有大写字符为小写 2.语法 str.lower() -> str 3.返回值 返回将字符串中的所有大写字母转换为小写字母的字符串 4.使用实例 #!/usr/bin/python3 str = "ABCDEFG" pr

  • python中Array和DataFrame相互转换的实例讲解

    python中,对于array数组中的数据放在DataFrame数据框中可以更好的进行数据分析,但是二者并不是一个数据类型,因此需要将array转dataframe.既然可以array转dataframe,那么可同样dataframe也可以转回array结构.本文介绍python中Array和DataFrame相互转换的方法. 1.array转dataframe:直接用pd.dataframe()进行转化 使用格式 a = pd.DataFrame(a) 具体实例 import pandas a

  • python中lstrip()截掉字符的实例讲解

    1.说明 lstrip() 方法用于截掉字符串左边的空格或指定的字符. 2.语法 str.lstrip([chars]) 3.参数说明 str:原字符串. chars:指定要截掉的字符串,可以是一个字符,或者多个字符,匹配时不是按照整个字符串匹配的,而是按照顺序一个个字符匹配的. 4.返回值 返回截掉字符串左边的空格或指定字符后生成的新字符串. 5.实例 str = " www. manhuan. net " str_val = str.lstrip() print(str_val)

随机推荐