Python開發(fā):緩存機(jī)制介紹
譯文【51CTO快譯】在今天的文章中,我們將一同從簡單示例出發(fā),了解如何使用緩存機(jī)制。在此之后,我們將進(jìn)一步利用Python標(biāo)準(zhǔn)庫的functools模塊創(chuàng)建適合自己需要的緩存。閑言少敘,馬上開始。
緩存是一種將定量數(shù)據(jù)加以保存以備迎合后續(xù)請(qǐng)求的處理方式,旨在加快數(shù)據(jù)的檢索速度。在今天的文章中,我們將一同從簡單示例出發(fā),了解如何使用緩存機(jī)制。在此之后,我們將進(jìn)一步利用Python標(biāo)準(zhǔn)庫的functools模塊創(chuàng)建適合自己需要的緩存。作為起步工作,我們首先創(chuàng)建一個(gè)類,用于構(gòu)建我們的緩存字典,而后根據(jù)需要進(jìn)行擴(kuò)展。以下為具體代碼:
- ########################################################################
- class MyCache:
- """"""
- #----------------------------------------------------------------------
- def __init__(self):
- """Constructor"""
- self.cache = {}
- self.max_cache_size = 10
在以上類示例中沒有包含什么特別之處。我們只是創(chuàng)建一個(gè)簡單類,同時(shí)設(shè)置兩個(gè)類變量或者說屬性,即cahce與max_cache_size。其中cache屬于一套空字典,而max_cache_size顯然代表著***緩存容量。下面讓我們進(jìn)一步充實(shí)該代碼,使其具備一定功能:
- import datetime
- import random
- ########################################################################
- class MyCache:
- """"""
- #----------------------------------------------------------------------
- def __init__(self):
- """Constructor"""
- self.cache = {}
- self.max_cache_size = 10
- #----------------------------------------------------------------------
- def __contains__(self, key):
- """
- 根據(jù)該鍵是否存在于緩存當(dāng)中返回True或者False
- """
- return key in self.cache
- #----------------------------------------------------------------------
- def update(self, key, value):
- """
- 更新該緩存字典,您可選擇性刪除最早條目
- """
- if key not in self.cache and len(self.cache) >= self.max_cache_size:
- self.remove_oldest()
- self.cache[key] = {'date_accessed': datetime.datetime.now(),
- 'value': value}
- #----------------------------------------------------------------------
- def remove_oldest(self):
- """
- 刪除具備最早訪問日期的輸入數(shù)據(jù)
- """
- oldest_entry = None
- for key in self.cache:
- if oldest_entry == None:
- oldest_entry = key
- elif self.cache[key]['date_accessed'] < self.cache[oldest_entry][
- 'date_accessed']:
- oldest_entry = key
- self.cache.pop(oldest_entry)
- #----------------------------------------------------------------------
- @property
- def size(self):
- """
- 返回緩存容量大小
- """
- return len(self.cache)
在這里,我們導(dǎo)入了datetime與random模塊,而后我們即可看到之前創(chuàng)建完成的類。這一次,我們向其中添加幾種方法。其中一種方法具備神奇的效果,名為_contains_。雖然在這里并不一定要使用該方法,但其基本思路在于允許我們檢查該類實(shí)例,從而了解其中是否包含有我們正在尋找的鍵。另外,update方法負(fù)責(zé)利用新的鍵/值對(duì)進(jìn)行緩存字典更新。一旦達(dá)到或者超出緩存***容量,其還會(huì)刪除日期最早的輸入數(shù)據(jù)。另外,remove_oldest方法負(fù)責(zé)具體的字典內(nèi)早期數(shù)據(jù)刪除工作。***,我們還引入了名為size的屬性,其能夠返回緩存的具體容量。
在添加了以下代碼之后,我們就能夠測試該緩存是否按預(yù)期起效:
- if __name__ == '__main__':
- #測試緩存
- keys = ['test', 'red', 'fox', 'fence', 'junk',
- 'other', 'alpha', 'bravo', 'cal', 'devo',
- 'ele']
- s = 'abcdefghijklmnop'
- cache = MyCache()
- for i, key in enumerate(keys):
- if key in cache:
- continue
- else:
- value = ''.join([random.choice(s) for i in range(20)])
- cache.update(key, value)
- print("#%s iterations, #%s cached entries" % (i+1, cache.size))
在本示例當(dāng)中,我們?cè)O(shè)置了大量預(yù)定義鍵與循環(huán)。如果鍵尚不存在,我們會(huì)將其添加到緩存當(dāng)中。不過以上示例代碼并沒有提到如何更新訪問日期,感興趣的朋友們可以將其作為練習(xí)自行探索。在運(yùn)行這段代碼之后,大家會(huì)注意到當(dāng)緩存被占滿時(shí),其會(huì)正確刪除時(shí)間更早的條目。
現(xiàn)在,我們繼續(xù)前進(jìn),看看如何利用另一種方式使用Python的內(nèi)置functools模塊創(chuàng)建緩存。
使用functools.lru_cache
Python的functools模塊提供一種非常實(shí)用的裝飾器,即lru_cache。需要注意的是,其在3.2版本當(dāng)中才被添加進(jìn)來。根據(jù)說明文檔所言,該裝飾器能夠“利用可調(diào)用內(nèi)存對(duì)函數(shù)進(jìn)行打包,從而削減最近調(diào)用的***尺寸。”接下來,我們將根據(jù)說明文檔中提到的示例編寫一項(xiàng)基本功能,其中包含多個(gè)網(wǎng)絡(luò)頁面。在這種情況下,我們可以直接從Python說明文檔站點(diǎn)處獲取頁面。
- import urllib.error
- import urllib.request
- from functools import lru_cache
- @lru_cache(maxsize=24)
- def get_webpage(module):
- """
- 獲取特定Python模塊網(wǎng)絡(luò)頁面
- """
- webpage = "https://docs.python.org/3/library/{}.html".format(module)
- try:
- with urllib.request.urlopen(webpage) as request:
- return request.read()
- except urllib.error.HTTPError:
- return None
- if __name__ == '__main__':
- modules = ['functools', 'collections', 'os', 'sys']
- for module in modules:
- page = get_webpage(module)
- if page:
- print("{} module page found".format(module))
在以上代碼當(dāng)中,我們利用lru_cache對(duì)get_webpage函數(shù)進(jìn)行了裝飾,并將其***尺寸設(shè)置為24條調(diào)用。在此之后,我們?cè)O(shè)置了一條網(wǎng)頁字符串變量,并將其傳遞至我們希望函數(shù)獲取的模塊當(dāng)中。根據(jù)我的個(gè)人經(jīng)驗(yàn),如果大家將其運(yùn)行在某種Python解釋器當(dāng)中——例如IDLE——那么效果會(huì)更好。如此一來,我們就能夠針對(duì)該函數(shù)運(yùn)行多次循環(huán)??梢钥吹皆?**運(yùn)行上述代碼時(shí),輸出結(jié)果的顯示速度相對(duì)比較慢。但如果大家在同一會(huì)話中再次加以運(yùn)行,那么其顯示速度將極大加快——這意味著lru_cache已經(jīng)正確對(duì)該調(diào)用進(jìn)行了緩存處理。大家可以在自己的解釋器實(shí)例當(dāng)中進(jìn)行試驗(yàn)并親自查看結(jié)果。
另外,我們還可以將一條typed參數(shù)傳遞至該裝飾器。其屬于一條Boolean,旨在通知該裝飾器在typed為設(shè)定為True時(shí)對(duì)不同類型參數(shù)進(jìn)行分別緩存。
總結(jié)
現(xiàn)在大家已經(jīng)初步了解了如何利用Python編寫自己的緩存機(jī)制。這是一款有趣的工具,而且能夠在各位面對(duì)大量高強(qiáng)度I/O調(diào)用或者希望對(duì)登錄憑證等常用信息進(jìn)行緩存時(shí)發(fā)揮重要作用。
原文標(biāo)題:Python開發(fā):緩存機(jī)制介紹
【51CTO譯稿,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文譯者和出處為51CTO.com】