說(shuō)說(shuō) Python 的 lru_cache 裝飾器

Python 的 lru_cache 裝飾器是一個(gè)為自定義函數(shù)提供緩存功能的裝飾器。其內(nèi)部會(huì)在下次以相同參數(shù)調(diào)用該自定義函數(shù)時(shí)直接返回計(jì)算好的結(jié)果。通過(guò)緩存計(jì)算結(jié)果可以很好地提升性能。

1 從示例說(shuō)起

假設(shè)我們有一個(gè)計(jì)算斐波那契數(shù)列的求和函數(shù),其內(nèi)部采用遞歸方式實(shí)現(xiàn)。

from xxx.clock_decorator import clock

@clock
def fibonacci(n):
    if n<2:
        return n
    return fibonacci(n-2)+fibonacci(n-1)

if __name__=='__main__':
    logging.info('fibonacci(6) -> %s',fibonacci(6))

運(yùn)行結(jié)果:


其中的 clock_decorator 實(shí)現(xiàn)是一個(gè)可以輸出某個(gè)函數(shù)運(yùn)行時(shí)長(zhǎng)的裝飾器1。

從輸出結(jié)果中可以看出,存在著嚴(yán)重的重復(fù)計(jì)算情況,比如 fibonacci(1) 就被計(jì)算了 5 次之多。這還只是計(jì)算 6 次的 fibonacci 函數(shù)。

2 優(yōu)化

上面的示例代碼加入 lru_cache 裝飾器:


運(yùn)行結(jié)果:


這次不存在重復(fù)計(jì)算現(xiàn)象,因此性能得到極大的提升。

3 比較

利用 cProfile 進(jìn)行性能比較分析。它是一種確定性分析器,只測(cè)量 CPU 時(shí)間,并不包含內(nèi)存消耗和其他與內(nèi)存相關(guān)聯(lián)的信息2。

假設(shè)我們需要計(jì)算 fibonacci(33) 求和值。

(1)不使用 lru_cache 裝飾器

這個(gè)遞歸函數(shù)內(nèi)部總共調(diào)用了 1000 多萬(wàn)次的 fibonacci() 函數(shù)!

(2)使用了 lru_cache 裝飾器

使用了 lru_cache 裝飾器之后,這個(gè)遞歸函數(shù)只需調(diào)用 100 多次fibonacci() 函數(shù)!性能有了質(zhì)的提升。

4 lru_cache 裝飾器

lru_cache 裝飾器支持兩個(gè)入?yún)?,它的完整定義格式為3
@functools.lru_cache(maxsize=128, typed=False)

參數(shù) 默認(rèn)值 說(shuō)明
maxsize 128 表示緩存大小。如果設(shè)置為 None,則不限大??;如果超過(guò)緩存大小,則使用 LRU 策略清理緩存。緩存的大小限制可確保緩存不會(huì)無(wú)限制增長(zhǎng)。LRU(Least Recently Used),即刪除最近最少使用的緩存數(shù)據(jù)。
typed False 如果為true,不同類型的參數(shù)將會(huì)被分別緩存,比如區(qū)分浮點(diǎn)數(shù)與整型。

注意:由于使用了字典來(lái)存儲(chǔ)緩存,所以所裝飾的函數(shù)參數(shù)必須是可哈希的。

利用 cache_info() 函數(shù),我們還可以看到命中次數(shù) hits,未命中次數(shù) misses ,最大緩存數(shù)量 maxsize 和 當(dāng)前緩存大小 currsize。使用方式是直接調(diào)用被裝飾函數(shù)的 cache_info(),形如:fibonacci.cache_info())。


只要某個(gè)函數(shù)遞歸調(diào)用并存在重復(fù)計(jì)算的情況,這時(shí)就要記著使用 lru_cache 這個(gè)性能加速器。


  1. 說(shuō)說(shuō)在 Python 中如何實(shí)現(xiàn)輸出指定函數(shù)運(yùn)行時(shí)長(zhǎng)的裝飾器.
  2. 說(shuō)說(shuō)如何使用 Python 的 cProfile 模塊分析代碼性能.
  3. Python docs lru_cache.
  4. Luciano Ramalho (作者),安道,吳珂 (譯者).流暢的Python[M].人民郵電出版社,2017:323-326.
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文的文字及圖片來(lái)源于網(wǎng)絡(luò),僅供學(xué)習(xí)、交流使用,不具有任何商業(yè)用途,如有問(wèn)題請(qǐng)及時(shí)聯(lián)系我們以作處理 最近閱讀《流暢...
    葡萄_ac1c閱讀 248評(píng)論 0 0
  • 人們總說(shuō)時(shí)間會(huì)改變一切,但是實(shí)際上你需要自己努力去改變! Python 小技巧 —— 用類寫裝飾器Python裝飾...
    BeautifulSoulpy閱讀 8,742評(píng)論 0 6
  • 緩存是一種將定量數(shù)據(jù)加以保存以備迎合后續(xù)獲取需求的處理方式,旨在加快數(shù)據(jù)獲取的速度。數(shù)據(jù)的生成過(guò)程可能需要經(jīng)過(guò)計(jì)算...
    水之心閱讀 4,952評(píng)論 0 3
  • 使用裝飾器lru_cache加速函數(shù)計(jì)算lru是一種緩存淘汰算法(least recently used)即最近最...
    清晨我上馬閱讀 787評(píng)論 0 0
  • 部分細(xì)節(jié)自己改了點(diǎn),也加了點(diǎn)自己例子,基本上屬于轉(zhuǎn)載。轉(zhuǎn)載出處:https://my.oschina.net/le...
    洛克黃瓜閱讀 2,102評(píng)論 0 3

友情鏈接更多精彩內(nèi)容