攝影:產品經理
下廚:kingname
在一日一技:實現函數調用結果的 LRU 緩存一文中,咱們提到Python自帶的LRU緩存lru_cache。經過這個裝飾器能夠很是輕鬆地實現緩存。redis
如今咱們考慮下面這個應用場景:MongoDB中有100對id-用戶名的對應關係,我從Redis中持續不斷讀取id,若是id能在MongoDB中找到對應關係,那麼就把對應的用戶名打印出來。若是找不到對應關係,那麼就把這個id丟棄。緩存
爲了防止頻繁讀取MongoDB,我在程序開始的時候直接讀取這一百對對應關係,並存爲字典:ide
import pymongo import redis client = redis.Redis() handler = pymongo.MongoClient().weibo.id_name_map def read_id_name_map(): id_name = {} for row in handler.find(): id_name[row['id']] = row['name'] return id_name id_name_map = read_id_name_map() while True: data = client.blpop('weibo_id') user_id = data[1].decode() if user_id in id_name_map: print(id_name_map[user_id])
你們能夠思考一下,上面這段代碼有沒有什麼問題。而後繼續看後面。函數
若是我如今須要再增長100個id-用戶名的對應關係怎麼辦?編碼
因爲這個程序運行之後就一直阻塞式地讀取Redis,不會中止,因此整個過程只會讀取一次MongoDB。後面即便我向MongoDB中添加了新的對應關係,只要程序不重啓,就沒法讀取到新的對應關係。code
確定有同窗想到,在while循環裏面增長一個計時器,每x分鐘就從新調用一下read_id_name_map()函數,更新對應關係。blog
不過今天咱們要講的是另外一個更有創意的辦法,使用lru_cache來實現。產品
對於這個例子來講,lru_cache的maxsize參數只須要設置爲1,由於只須要存放1份對應關係便可。那麼咱們如何作到,好比每10分鐘更新一次呢?咱們知道,在使用lru_cache時,若是調用同一個函數,而且傳入的參數相同,那麼從第二次開始就會使用緩存。如今咱們如何讓時間在每10分鐘內相同呢?it
咱們來看如今的時間戳:1578399211.30042class
它除以600,值是1578399211.30042 // 600 = 2630665.0。而後我讓這個時間戳加5分鐘,也就是增長300秒,變成1578399511.30042。這個新的時間戳再除以600,發現結果仍是2630665.0。但若是原來的時間戳增長超過10分鐘,例如增長了601秒,咱們再來看看效果(1578399211.30042 + 601) // 600 = 2630666.0,此時的結果也發生了變化。
利用這個特色,修改一下咱們的代碼:
import pymongo import redis import time from functools import lru_cache client = redis.Redis() handler = pymongo.MongoClient().weibo.id_name_map @lru_cache(maxsize=1) def read_id_name_map(_): id_name = {} for row in handler.find(): id_name[row['id']] = row['name'] return id_name while True: data = client.blpop('weibo_id') id_name_map = read_id_name_map(time.time() // 600) user_id = data[1].decode() if user_id in id_name_map: print(id_name_map[user_id])
如今,咱們直接在while循環內部調用read_id_name_map,若是兩次調用的時間間隔小於600秒,那麼time.time() // 600的值是相同的,第二次直接使用緩存,也就不會查詢MongoDB了。當時間超過10分鐘後,時間戳除以600的值增長了,因而緩存沒有命中,進入查詢MongoDB的過程,更新id_name_map。實現了有過時時間的LRU緩存。
補充:可能有同窗注意到定義read_id_name_map函數的時候,參數我寫的是下劃線。這是Python 編碼規範中建議的一種寫法。當一個變量不會被使用,但又須要保留時,就能夠用下劃線表示。