網(wǎng)站首頁 編程語言 正文
一、前言
我們經(jīng)常談?wù)摰木彺嬉辉~,更多的類似于將硬盤中的數(shù)據(jù)存放到內(nèi)存中以至于提高讀取速度,比如常說的redis,就經(jīng)常用來做數(shù)據(jù)的緩存。
Python的緩存(lru_cache)是一種裝飾在被執(zhí)行的函數(shù)上,將其執(zhí)行的結(jié)果緩存起來,當(dāng)下次請求的時(shí)候,如果請求該函數(shù)的傳參未變則直接返回緩存起來的結(jié)果而不再執(zhí)行函數(shù)的一種緩存裝飾器。
那它和redis的區(qū)別在哪?有什么優(yōu)勢?怎么使用? 下面為你講解
二、舉例說明
1.現(xiàn)在我們先不使用緩存來寫一個(gè)求兩數(shù)之和的函數(shù),并調(diào)用執(zhí)行它兩次:
def test(a, b): print('開始計(jì)算a+b的值...') return a + b print('1+2等于:', test(1, 2)) print('1+2等于:', test(1, 2))
執(zhí)行結(jié)果
開始計(jì)算a+b的值...
1+2等于: 3
開始計(jì)算a+b的值...
1+2等于: 3
可以看到test被執(zhí)行了兩次,現(xiàn)在我們加上緩存再進(jìn)行執(zhí)行:
from functools import lru_cache @lru_cache def test(a, b): print('開始計(jì)算a+b的值...') return a + b print(test(1, 2)) print(test(1, 2))
執(zhí)行結(jié)果
開始計(jì)算a+b的值...
1+2等于: 3
1+2等于: 3
可以看到test函數(shù)只被執(zhí)行了一次,第二次的調(diào)用直接輸出了結(jié)果,使用了緩存起來的值。
2.當(dāng)我們使用遞歸求斐波拉契數(shù)列 (斐波那契數(shù)列指的是這樣一個(gè)數(shù)列:0,1,1,2,3,5,8,它從第3項(xiàng)開始,每一項(xiàng)都等于前兩項(xiàng)之和) 的時(shí)候,緩存對性能的提升就尤其明顯了:
不使用緩存求第40項(xiàng)的斐波拉契數(shù)列
import datetime def fibonacci(num): # 不使用緩存時(shí),會(huì)重復(fù)執(zhí)行函數(shù) return num if num < 2 else fibonacci(num - 1) + fibonacci(num - 2) start = datetime.datetime.now() print(fibonacci(40)) end = datetime.datetime.now() print('執(zhí)行時(shí)間', end - start)
執(zhí)行時(shí)間
執(zhí)行時(shí)間 0:00:29.004424
使用緩存求第40項(xiàng)的斐波拉契數(shù)列:
import datetime def fibonacci(num): # 不使用緩存時(shí),會(huì)重復(fù)執(zhí)行函數(shù) return num if num < 2 else fibonacci(num - 1) + fibonacci(num - 2) start = datetime.datetime.now() print(fibonacci(40)) end = datetime.datetime.now() print('執(zhí)行時(shí)間', end - start)
執(zhí)行時(shí)間
執(zhí)行時(shí)間 0:00:00
兩個(gè)差距是非常明顯的,因?yàn)椴皇褂镁彺鏁r(shí),相當(dāng)于要重復(fù)執(zhí)行了很多的函數(shù),而使用了lru_cache則把之前執(zhí)行的函數(shù)結(jié)果已經(jīng)緩存了起來,就不需要再次執(zhí)行了。
三、lru_cache 用法
1.參數(shù)詳解
查看lru_cache源碼會(huì)發(fā)現(xiàn)它可以傳遞兩個(gè)參數(shù):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裝飾的方法最大可緩存的結(jié)果數(shù)量 (被裝飾方法傳參不同一樣,則結(jié)果不一樣;如果傳參一樣則為同一個(gè)結(jié)果), 如果不指定傳參則默認(rèn)值為128,表示最多緩存128個(gè)返回結(jié)果,當(dāng)達(dá)到了128個(gè)時(shí),有新的結(jié)果要保存時(shí),則會(huì)刪除最舊的那個(gè)結(jié)果。如果maxsize傳入為None則表示可以緩存無限個(gè)結(jié)果;
2)typed
默認(rèn)為false,代表不區(qū)分?jǐn)?shù)據(jù)類型,如果設(shè)置為True,則會(huì)區(qū)分傳參類型進(jìn)行緩存,官方是這樣描述的:
如果typed為True,則將分別緩存不同類型的參數(shù),
例如,f(3.0)和f(3)將被視為具有明顯的結(jié)果。
但在python3.9.8版本下進(jìn)行測試,typed為false時(shí),按照官方的測試方法測試得到的還是會(huì)被當(dāng)成不同的結(jié)果處理,這個(gè)時(shí)候typed為false還是為true都會(huì)區(qū)別緩存,這與官方文檔的描述存在差異:
from functools import lru_cache @lru_cache def test(a): print('函數(shù)被調(diào)用了...') return a print(test(1.0)) print(test(1))
執(zhí)行結(jié)果
函數(shù)被調(diào)用了...
1.0
函數(shù)被調(diào)用了...
但如果是多參數(shù)的情況下,則會(huì)被當(dāng)成一個(gè)結(jié)果:
from functools import lru_cache @lru_cache def test(a, b): print('函數(shù)被調(diào)用了...') return a , b print(test(1.0, 2.0)) print(test(1, 2))
執(zhí)行結(jié)果
函數(shù)被調(diào)用了...
(1.0, 2.0)
(1.0, 2.0)
這個(gè)時(shí)候設(shè)置typed為true時(shí),則會(huì)區(qū)別緩存:
from functools import lru_cache @lru_cache(typed=True) def test(a, b): print('函數(shù)被調(diào)用了...') return a , b print(test(1.0, 2.0)) print(test(1, 2))
執(zhí)行結(jié)果
函數(shù)被調(diào)用了...
(1.0, 2.0)
函數(shù)被調(diào)用了...
(1, 2)
當(dāng)傳參個(gè)數(shù)大于1時(shí),才符合官方的說法,不清楚是不是官方舉例有誤
2. lru_cache不支持可變參數(shù)
當(dāng)傳遞的參數(shù)是dict、list等的可變參數(shù)時(shí),lru_cache是不支持的,會(huì)報(bào)錯(cuò):
from functools import lru_cache @lru_cache def test(a): print('函數(shù)被執(zhí)行了...') return a print(test({'a':1}))
報(bào)錯(cuò)結(jié)果
TypeError: unhashable type: 'dict'
四、lru_cache 與redis的區(qū)別
緩存 | 緩存位置 | 是否支持可變參數(shù) | 是否支持分布式 | 是否支持過期時(shí)間設(shè)置 | 支持的數(shù)據(jù)結(jié)構(gòu) | 需單獨(dú)安裝 |
---|---|---|---|---|---|---|
redis | 緩存在redis管理的內(nèi)存中 | 是 | 是 | 是 | 支持5種數(shù)據(jù)結(jié)構(gòu) | 是 |
lru_cache | 緩存在應(yīng)用進(jìn)程的內(nèi)存中,應(yīng)用被關(guān)閉則被清空 | 否 | 否 | 否 | 字典(參數(shù)為:key,結(jié)果為:value) | 否 |
五、總結(jié)
經(jīng)過上面的分析,lru_cache 功能相對于redis來說要簡單許多,但使用起來更加方便,適用于小型的單體應(yīng)用。如果涉及的緩存的數(shù)據(jù)種類比較多并且想更好的管理緩存、或者需要緩存數(shù)據(jù)有過期時(shí)間(類似登錄驗(yàn)證的token)等,使用redis是優(yōu)于lru_cache的。
原文鏈接:https://blog.csdn.net/momoda118/article/details/120726050
相關(guān)推薦
- 2022-06-10 C++?STL?中的數(shù)值算法示例講解_C 語言
- 2022-12-08 用C語言求解一元二次方程的簡單實(shí)現(xiàn)_C 語言
- 2022-07-21 Pandas文件讀寫操作
- 2022-02-14 小程序使用了scroll-view滾動(dòng)組件時(shí),如何判斷滾動(dòng)的方向
- 2022-05-26 pandas進(jìn)行數(shù)據(jù)輸入和輸出的方法詳解_python
- 2022-07-31 C++超詳細(xì)分析講解內(nèi)聯(lián)函數(shù)_C 語言
- 2023-05-08 Docker中的compose簡介_docker
- 2022-09-10 詳解Go?中的時(shí)間處理_Golang
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支