一、前言 我们经常谈论的缓存一词,更多的类似于将硬盘中的数据存放到内存中以至于提高读取速度,比如常说的redis,就经常用来做数据的缓存。Python的缓存(lrucache)是一种装饰在被执行的函数上,将其执行的结果缓存起来,当下次请求的时候,如果请求该函数的传参未变则直接返回缓存起来的结果而不再执行函数的一种缓存装饰器。 那它和redis的区别在哪?有什么优势?怎么使用?下面为你讲解二、举例说明 1。现在我们先不使用缓存来写一个求两数之和的函数,并调用执行它两次:deftest(a,b):print(开始计算ab的值。。。)returnabprint(12等于:,test(1,2))print(12等于:,test(1,2)) 执行结果开始计算ab的值。。。12等于:3开始计算ab的值。。。12等于:3 可以看到test被执行了两次,现在我们加上缓存再进行执行:fromfunctoolsimportlrucachelrucachedeftest(a,b):print(开始计算ab的值。。。)returnabprint(test(1,2))print(test(1,2)) 执行结果开始计算ab的值。。。12等于:312等于:3 可以看到test函数只被执行了一次,第二次的调用直接输出了结果,使用了缓存起来的值。 2。当我们使用递归求斐波拉契数列(斐波那契数列指的是这样一个数列:0,1,1,2,3,5,8,它从第3项开始,每一项都等于前两项之和)的时候,缓存对性能的提升就尤其明显了: 不使用缓存求第40项的斐波拉契数列importdatetimedeffibonacci(num):不使用缓存时,会重复执行函数returnnumifnum2elsefibonacci(num1)fibonacci(num2)startdatetime。datetime。now()print(fibonacci(40))enddatetime。datetime。now()print(执行时间,endstart) 执行时间执行时间0:00:29。004424 使用缓存求第40项的斐波拉契数列:lrucachedeffibonacci(num):不使用缓存时,会重复执行函数returnnumifnum2elsefibonacci(num1)fibonacci(num2) 执行时间执行时间0:00:00 两个差距是非常明显的,因为不使用缓存时,相当于要重复执行了很多的函数,而使用了lrucache则把之前执行的函数结果已经缓存了起来,就不需要再次执行了。三、lrucache用法1。参数详解 查看lrucache源码会发现它可以传递两个参数:maxsize、typed:deflrucache(maxsize128,typedFalse):Leastrecentlyusedcachedecorator。IfmaxsizeissettoNone,theLRUfeaturesaredisabledandthecachecangrowwithoutbound。。。。1)maxsize 代表被lrucache装饰的方法最大可缓存的结果数量(被装饰方法传参不同一样,则结果不一样;如果传参一样则为同一个结果),如果不指定传参则默认值为128,表示最多缓存128个返回结果,当达到了128个时,有新的结果要保存时,则会删除最旧的那个结果。如果maxsize传入为None则表示可以缓存无限个结果;2)typed 默认为false,代表不区分数据类型,如果设置为True,则会区分传参类型进行缓存,官方是这样描述的: 如果typed为True,则将分别缓存不同类型的参数,例如,f(3。0)和f(3)将被视为具有明显的结果。 但在python3。9。8版本下进行测试,typed为false时,按照官方的测试方法测试得到的还是会被当成不同的结果处理,这个时候typed为false还是为true都会区别缓存,这与官方文档的描述存在差异:fromfunctoolsimportlrucachelrucachedeftest(a):print(函数被调用了。。。)returnaprint(test(1。0))print(test(1)) 执行结果函数被调用了。。。1。0函数被调用了。。。1 但如果是多参数的情况下,则会被当成一个结果:fromfunctoolsimportlrucachelrucachedeftest(a,b):print(函数被调用了。。。)returna,bprint(test(1。0,2。0))print(test(1,2)) 执行结果函数被调用了。。。(1。0,2。0)(1。0,2。0) 这个时候设置typed为true时,则会区别缓存:fromfunctoolsimportlrucachelrucache(typedTrue)deftest(a,b):print(函数被调用了。。。)returna,bprint(test(1。0,2。0))print(test(1,2)) 执行结果函数被调用了。。。(1。0,2。0)函数被调用了。。。(1,2) 当传参个数大于1时,才符合官方的说法,不清楚是不是官方举例有误2。lrucache不支持可变参数 当传递的参数是dict、list等的可变参数时,lrucache是不支持的,会报错:fromfunctoolsimportlrucachelrucachedeftest(a):print(函数被执行了。。。)returnaprint(test({a:1})) 报错结果TypeError:unhashabletype:dict四、lrucache与redis的区别 缓存缓存位置是否支持可变参数是否支持分布式是否支持过期时间设置支持的数据结构需单独安装redis缓存在redis管理的内存中是是是支持5种数据结构是lrucache缓存在应用进程的内存中,应用被关闭则被清空否否否字典(参数为:key,结果为:value)否五、总结 经过上面的分析,lrucache功能相对于redis来说要简单许多,但使用起来更加方便,适用于小型的单体应用。如果涉及的缓存的数据种类比较多并且想更好的管理缓存、或者需要缓存数据有过期时间(类似登录验证的token)等,使用redis是优于lrucache的。