一日一技:實現函數調用結果的 LRU 緩存

一日一技:實現函數調用結果的 LRU 緩存

一日一技:實現函數調用結果的 LRU 緩存

攝影:產品經理
在工程項目中,可能有一些函數調用耗時很長,但是又需要反覆多次調用,並且每次調用時,相同的參數得到的結果都是相同的。在這種情況下,我們可能會使用變量或者列表來存放,例如:

resp_1 = get_resp(param=1)
resp_2 = get_resp(param=2)
resp_3 = get_resp(param=3)

但是,如果返回的結果佔用內存比較大,我們每次調用都把結果存在內存裏面,就會消耗大量內存。

於是,我們可以使用 LRU 算法:最近最常使用的參數生成的結果,我們存下來,下次遇到相同的參數時直接返回結果。而不常出現的參數,等到需要的時候再計算。計算完成後,也先存下來。但是如果緩存空間不夠了,不常使用的會先刪除。

LRU 的算法自己手動實現起來比較麻煩,但好在 Python 的 functions模塊已經提供了現成的 lru_cache裝飾器供我們使用。

首先我們寫一個不帶 lru 算法的程序:

import time
import datetime
def say(name):
print(f'你好:{name}')
now = datetime.datetime.now()
return now
now = say('kingname')
print(f'現在時間爲:{now}')
time.sleep(10)
now = say('產品經理')
print(f'現在時間爲:{now}')
time.sleep(10)
now = say('kingname')
print(f'現在時間爲:{now}')

運行效果如下圖所示:
一日一技:實現函數調用結果的 LRU 緩存

從運行結果可以看到,調用函數三次,第一次和第三次傳入的參數都是 kingname,第二次傳入的參數爲 產品經理, 你好:kingname打印了兩次, 你會:產品經理打印了一次。第二次打印的時間比第一次多了10秒,第三次打印的時間比第二次多了10秒。

現在我們把 LRU 緩存加上。

import time
import datetime
from functools import lru_cache
@lru_cache(maxsize=32)
def say(name):
print(f'你好:{name}')
now = datetime.datetime.now()
return now
now = say('kingname')
print(f'現在時間爲:{now}')
tie.sleep(10)
now = say('產品經理')
print(f'現在時間爲:{now}')
time.sleep(10)
now = say('kingname')
print(f'現在時間爲:{now}')

一日一技:實現函數調用結果的 LRU 緩存

從打印出來的結果可以看出,第三次調用 say函數的時候,傳入的也是 kingname,但是函數根本沒有運行,所以沒有打印第二個 你好:kingname。並且第三個時間與第一個時間完全相同。說明第三次調用函數的時候,直接讀取的緩存。

lru_cache(maxsize=128,typed=False)接收兩個參數,第一個參數 maxsize表示最多緩存多少個結果,這個數字建議設置爲2的冪。超出這個結果就會啓用 LRU 算法刪除不常用的數據。第二個參數 typed表示是否檢查參數類型,默認爲 False,如果設置爲 True,那麼參數 3和 3.0會被當做不同的數據處理。

由於 lru_cache底層是基於字典來實現的緩存,所以參數都必須是 hashable 的,否則會導致報錯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章