摄影:产品经理
下厨: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 编码规范中建议的一种写法。当一个变量不会被使用,但又须要保留时,就能够用下划线表示。