1. 為什么需要緩存技術?
使用緩存是優(yōu)化Python程序速度的重要方法之一。如果使用得當,可以大幅減少計算資源的負載,有效加快代碼運行速度
Python 的內置庫 functools 模塊附帶了@lru_cache,@cache, @cached_property
裝飾器,使用非常簡便,不需要安裝第3方庫,不需要 redis 等數(shù)據(jù)庫保存對象等,通常只需要1行代碼,就可以對函數(shù)運算結果、類成員方法運算結果進行緩存。
本文將介紹這3種緩存工具的使用步驟及實例。
2. @lru_cache 緩存裝飾器的使用
@lru_cache 是最常見的緩存裝飾器。lru_cache
是: Last recently used cache
的簡寫,可以將該函數(shù)最近調用的輸入?yún)?shù)以及結果進行緩存。如果有新的調用,先檢查緩存是否有相同的輸入?yún)?shù),如果存在,則直接返回對應結果。如果是無參函數(shù),第1次調用后,以后每次調用,直接返回緩存結果。
先看1個例子
from functools import lru_cache
from math import sin
@lru_cache
def sin_half(x):
return sin(x)/2
print('first call result:',sin_half(60))
print('second call result:',sin_half(60))
上例中,第1次運行函數(shù)后,lru_cache會緩存調用參數(shù)及返回結果。第2次運行時,lru_cache都會檢查輸入,發(fā)現(xiàn)緩存中存在相同輸入?yún)?shù)60,則從緩存中返回結果。如果函數(shù)執(zhí)行的是計算量很重的任務,對于相同輸入,可以明顯地節(jié)省系統(tǒng)資源。
裝飾器參數(shù)
lru_cache默認不清除緩存內容,因此緩存會無限增長,如果程序是長期運行的服務,可能存在耗盡內存的風險。 因此,必須添加1個maxsize參數(shù):
@lru_cache(maxsize) 的參數(shù)maxsize 表示要緩存的最近調用次數(shù).
如 @lru_cache(360) 表示,只緩存最近360次的函數(shù)調用結果。
@lru_cache(360)
def sin_half(x):
return sin(x)/2
緩存操作
查看緩存報告: sin_half.cache_info()
強制清除緩存內容: sin_half.cache_clear()
當然也可以使用 python的 garbage collection 清除緩存。
下面使用1個示例來演示上述內容:
import functools
import gc
# 主要功能:
# 驗證 @lru_cache 裝飾器,.chche_info() 和 .cache_clear() 方法的使用
# garbage collection 的使用
@functools.lru_cache(maxsize = 300) # Max number of Last recently used cache
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
fib(30)
fib.cache_clear()
# Before Clearing
print(fib.cache_info())
# After Clearing
print(fib.cache_info())
@functools.lru_cache(maxsize = None)
def gfg1():
# insert function logic here
pass
# 再次運行函數(shù)
gfg1()
fib(30)
# garbage collection
gc.collect()
# All objects collected
objects = [i for i in gc.get_objects()
if isinstance(i, functools._lru_cache_wrapper)]
print(gfg1.cache_info())
# All objects cleared
for object in objects:
object.cache_clear()
print(gfg1.cache_info())
運行程度,輸出為:
CacheInfo(hits=0, misses=0, maxsize=300, currsize=0)
CacheInfo(hits=0, misses=0, maxsize=300, currsize=0)
CacheInfo(hits=0, misses=1, maxsize=None, currsize=1)
CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)
3. @cache 緩存裝飾器的使用
相比@lru_cache, @cache 裝飾器更輕量化,速度更快,且是線程安全,不同線程可以調用同1個函數(shù),緩存值可以共享。
import functools
import time
@functools.cache
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
if __name__ == '__main__':
start_time = time.time()
print(fib(400))
end_time = time.time()
execution_time_without_cache = end_time - start_time
print("Time taken without cache: {:.8f} seconds".format(execution_time_without_cache))
start_time = time.time()
print(fib(400))
end_time = time.time()
execution_time_without_cache = end_time - start_time
print("Time taken with cache: {:.8f} seconds".format(execution_time_without_cache))
output:
176023680645013966468226945392411250770384383304492191886725992896575345044216019675
Time taken without cache: 0.00095391 seconds
176023680645013966468226945392411250770384383304492191886725992896575345044216019675
Time taken with cache: 0.00000000 seconds
4. @cached_property 緩存裝飾器的使用
@cached_property
是一個裝飾器,它將類的方法轉換為屬性,其值僅計算一次,然后緩存為普通屬性。因此,只要實例持久存在,緩存的結果就可用,我們可以將該方法用作類的屬性那樣來使用,如
調用: : instance.method
取代舊方式 : instance.method()
@cached_property
是 Python 中 functools 模塊的一部分。它類似于 property()
,但 @cached_property
帶有一個額外的功能,那就是緩存。
但是它如何減少執(zhí)行時間并使程序更快?請考慮以下示例:
# Without using @cached_property
# A sample class
class Sample():
def __init__(self, lst):
self.long_list = lst
# a method to find the sum of the
# given long list of integer values
def find_sum(self):
return (sum(self.long_list))
# obj is an instance of the class sample
# the list can be longer, this is just
# an example
obj = Sample([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(obj.find_sum())
print(obj.find_sum())
print(obj.find_sum())
輸出為:
55
55
55
在這里,假設如果我們傳遞1個長列表,每次調用 find_sum()方法時都會計算給定列表的總和,從而花費大量時間運行,程序最終會變慢。我們想要的是,由于列表在創(chuàng)建實例后不會更改,因此,如果列表的總和只計算一次,而不是每次在我們調用方法并希望訪問總和時計算,那就太好了。這可以通過使用@cached_property來實現(xiàn),
# With using @cached_property
from functools import cached_property
# A sample class
class Sample():
def __init__(self, lst):
self.long_list = lst
# a method to find the sum of the
# given long list of integer values
@cached_property
def find_sum(self):
return (sum(self.long_list))
# obj is an instance of the class sample
obj = Sample([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(obj.find_sum)
print(obj.find_sum)
print(obj.find_sum)
使用了@cached_property裝飾器后,無須重新計算,總是立即返回find_sum值。
如果需要重新計算屬性,則刪除該屬性即可,下次調用會重新計算,在本例 中添加如下語句,
del obj.find_sum
obj.long_list = range(20,30)
print(obj.find_sum)
運行代碼,輸出結果為:文章來源:http://www.zghlxwxcb.cn/news/detail-515076.html
55
55
55
245
5. 各種緩存方法的適用場景
綜上所述,建議如下:
1) 如果程序規(guī)模小,或多線程編程時,可使用@cache 裝飾器。
2) 如果程度規(guī)模大,并且是長時間運行,建議使用@lru_cache 裝飾器,使用方法靈活,但要注意控制緩存數(shù)量,必要時手工清理。
3) 編寫類代碼時,如需將某項復雜運算結果像屬性那樣訪問時,使用@cached_property裝飾器。文章來源地址http://www.zghlxwxcb.cn/news/detail-515076.html
到了這里,關于如何使用Python內置緩存裝飾器: @lru_cache,@cache 與 @cached_property的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!