Python 如何手动编写一个自己的LRU缓存装饰器的方法实现
作者:蠢萌的二狗子 发布时间:2022-08-04 13:06:10
标签:Python,LRU,缓存装饰器
LRU缓存算法,指的是近期最少使用算法,大体逻辑就是淘汰最长时间没有用的那个缓存,这里我们使用有序字典,来实现自己的LRU缓存算法,并将其包装成一个装饰器。
1、首先创建一个my_cache.py文件 编写自己我们自己的LRU缓存算法,代码如下:
import time
from collections import OrderedDict
'''
基于LRU,近期最少用缓存算法写的装饰器。
'''
class LRUCacheDict:
def __init__(self, max_size=1024, expiration=60):
self.max_size = max_size
self.expiration = expiration
self._cache = {}
self._access_records = OrderedDict() # 记录访问时间
self._expire_records = OrderedDict() # 记录失效时间
def __setitem__(self, key, value): # 设置缓存
now = int(time.time())
self.__delete__(key) # 删除原有使用该Key的所有缓存
self._cache[key] = value
self._access_records = now # 设置访问时间
self._expire_records = now + self.expiration # 设置过期时间
self.cleanup()
def __getitem__(self, key): # 更新缓存
now = int(time.time())
del self._access_records[key] # 删除原有的访问时按
self._access_records[key] = now
self.cleanup()
def __contains__(self, key): # 这个是字典默认调用key的方法
self.cleanup()
return key in self._cache
def __delete__(self, key):
if key in self._cache:
del self._cache[key] # 删除缓存
del self._access_records[key] # 删除访问时间
del self._expire_records[key] # 删除过期时间
def cleanup(self): # 用于去掉无效(超过大小)和过期的缓存
if self._expire_records is None:
return None
pending_delete_keys = []
now = int(time.time())
for k, v in self._expire_records.items(): # 判断缓存是否失效
if v < now:
pending_delete_keys.append(k)
for del_k in pending_delete_keys:
self.__delete__(del_k)
while len(self._cache) > self.max_size: # 判断缓存是否超过长度
for k in self._access_records.keys(): # LRU 是在这里实现的,如果缓存用的最少,那么它存入在有序字典中的位置也就最前
self.__delete__(k)
break
代码逻辑其实很简单,上面的注释已经很详细了,不懂的话多看几次。这里实现LRU逻辑的其实是有序字典OrderedDict,你最先存入的值就会存在字典的最前面。当一个值使用时候,我们会重新储存过期时间,导致被经常使用的缓存,会存在字典的后面。而一但缓存的内容长度超过限制时候,这里会调用有序字典最前面的key(也即是近期相对用的最少的),并删除对应的内容,以达到LRU的逻辑。
2、在将我们写好的算法改成装饰器:
from functools import wraps
from my_cache import LRUCacheDict
def lru_cache(max_size=1024, expiration=60, types='LRU'):
if types == 'lru' or types == 'LRU':
my_cache = LRUCacheDict(max_size=max_size, expiration=expiration)
def wrapper(func):
@wraps(func)
def inner(*args, **kwargs):
key = repr(*args, **kwargs)
try:
result = my_cache[key]
except KeyError:
result = func(*args, **kwargs)
my_cache[key] = result
return result
return inner
return wrapper
这里需要解释的是直接使用 my_cache[key],这个类似字典的方法,实际上是调用了 LRUCacheDict 中的 __contations__方法,这也是字典中实现通过key取值的方法。这个装饰器里,我加入了types的参数,你们可以根据需求,实现不同的缓存算法,丰富这个装饰器的功能,而lru缓存本身,其实已经是python的标准库了,可以引入functools.lru_cache来调用。
来源:https://blog.csdn.net/qq442000755/article/details/122150012
0
投稿
猜你喜欢
- 微信小程序全称微信公众平台·小程序,原名微信公众平台·应用号(简称微信应用号)声明•微信小程序开发工具类似于一个轻量级的IDE集成开发环境,
- 服务端监听端口 listen()方法:net.listen({监听类型},{监听的ip和端口})(conn, err){}返回值:conn是
- 前言Python 读取数据自动写入 MySQL 数据库,这个需求在工作中是非常普遍的,主要涉及到 python 操作数据库,读写更新等,数据
- AXObject可用来解决IE需要激活 ActiveX 控件和生成控件调用代码 AXObjec
- 一、上传表单的HTML代码 <form action="UpLoad.php" method="post
- 本文实例讲述了Python3的urllib.parse常用函数。分享给大家供大家参考,具体如下:1、获取url参数>>>
- 前言 日益增长的分布式应用需求要求实现更好分布式的软件环境,不断推动着分布式技术的进步。Oracle数据复制是实现分布式数据环境的一种技术,
- 不知道您是否留意了,浏览本站时,浏览器右下角有一个标着top的黑色直角三角形,可以点击它返回到正在浏览的网页页眉。当滚动网页时,它的位置一直
- phpMyAdmin是一个用PHP编写的,可以通过互联网控制和操作MySQL。通过phpMyAdmin可以完全对数据库进行操作,例如建立、复
- 看过一篇关于下载网页中图片的文章,它只能下载以http头的图片,我做了些改进,可以下载网页中的所有连接资源,并按照网页中的目录结构建立本地目
- 我一般是不看别人写的代码的,为啥?累!而且这位同志给的还是经过压缩的!汗。。。考我是不是?还有,这位同志也不给个示例的代码,只说是代码没有问
- apache对php的支持是通过apache的mod_php5模块来支持的,这点与nginx不同。nginx是通过第三方的fastcgi处理
- 开发微信小程序过程中,有个需求需要用到日期时间筛选器,查看微信官方文档后,发现官方文档的picker筛选器只能单独支持日期或者是时间,所以为
- 数据共享是数据库最基本的特征之一。但是数据共享虽然为员工带来了便利,但也产生了一些负面作用。例如因用户并发存取而导致的对数据一致性的破坏、由
- 这篇分享几个在地址栏实现的Javascript有趣效果和应用。能在浏览器地址栏实现的效果太多了,字体放大、显示所有图片、显示Cookie等等
- 使用python将图片改为灰度图或黑白图有三种方式,分别是是使用cv2库和PIL库来实现,详细过程如下所示。1. 使用cv2库将图片改为灰度
- 但是有时候,可以视看处进逻辑程度,可以把三者写成一个触发器,只是在其中稍作判断而已。 你可以根据从下面方法判断触发器是是处理了插入,删除还是
- 以下所描述无理论依据,纯属经验谈。MySQL使用4.1以上版本,管他是什么字符集,一律使用默认。不用去设置MySQL。然后举个使用GB231
- 1.nginx使用哪种网络协议? nginx是应用层 我觉得从下往上的话 传输层用的是tcp/ip 应用层用的是http fastcgi负责
- PHP重启php-fpm的方法启动php-fpm:/usr/local/php/sbin/php-fpmphp 5.3.3 以后的php-f