这篇“怎么用Python编写一个简单的缓存系统”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么用Python编写一个简单的缓存系统”文章吧。
本篇文章所依赖的
python环境为:
项目展示
该
demo将分为2个部分展示,第一个部分我们会写入一些
key和
value进入到缓存系统中,而后关闭程序。
第二部分则会去获取第一个部分写入的
key的名称。
第一部分
main方法如下:
def main() -> None: c = dbCache("db.cache") c.cacheSetting(queueMaxKeys=3,ageSec=3) c.set("name","pdudo") c.set("site","juejin") c.set("hello","word") c.set("hello","pdudo")
其中,
dbCache是我们定义的类,而
set是写入方法,
cacheSetting设置一些基础环境变量,例如:
queueMaxKeys: 需要制定增删改缓存队列,类型为
int,如果满了,则立即落地到磁盘中。
ageSec: 间隔时间,参数为秒数,若操作第一个
key和操作第二个
key时间大于该设置,则落地到磁盘。
set则是写入方法,参数为
key和
value。
运行后,代码效果如下:
由于我们只有
set,所以不会输出任何信息,上述
open file error是正常的警告信息,不用管它。
第一部分操作完毕了,我们可以修改第二部分,使用
get去获取第一次存储的数据。
修改
main如下:
def main() -> None: c = dbCache("db.cache") c.cacheSetting(queueMaxKeys=3,ageSec=3) print(c.get("name")) print(c.get("hello")) print(c.get("site"))
运行后,效果如下:
由此可以验证,从磁盘读取文件并且加载进内存,没什么问题。
除此之外,该库还支持其他操作,例如:
# 定义一个缓存对象 c = dbCache("db.cache") # 配置环境变量 c.cacheSetting(queueMaxKeys=3,ageSec=3) # 写 c.set("name","pdudo") # 读 print(c.get("name")) # 修改 c.update("name", "juejin") # 删除 c.delete("name")
接下来,我们就来看下,如何一步一步完成这个最简单的缓存系统。
不用落地的缓存系统系统应该如何实现
在
python中,给我们提供了很多基础的数据类型,例如 列表、字典等。所以说,就没必要自己在定义一套属于自己的数据类型了,可以直接使用现有的数据类型,例如本篇文章所使用的就是字典,这里简单的铺垫一下字典的增删改查。
铺垫python字典基本操作
定义一个空的字典
a,可以使用如下代码:
a = {}
写入
key可以直接使用
a[key] = value即可,例如:
a["name"] = "pdudo"
修改也是和上述一样的
关于查询,我们直接使用
a[key]即可。
若没有这个
key会抛错:
KeyError: 'key'。
print(a["name"])
检查是否存在
key,可以使用
key in dict来判断,例如: 想判断
name是否是字典
a中的
key,可以写为:
print("name" in a)
若存在于
a中,会返回
True,否则会返回
False。
定义一个不用落地的缓存系统
有了上述关于字典的基本操作,我们可以将其封装一下,定义为自己的操作方法,例如:
class cacheDB(): def __init__(self): #定义空的字典 self.cache = {} #增 def set(self,key,value): self.cache[key] = value #查 def get(self,key): return self.cache[key] #修 def update(self,key,value): self.cache[key] = value #删除 def delete(self,key): del self.cache[key] def main(): c = cacheDB() c. set("name","pdudo") print(c.get("name")) c.update("name","juejin") print(c.get("name")) c.delete("name") if __name__ == '__main__': main()
我们可以将上述方法,封装在一个
class中,从而实现调用。
例如,运行之后结果为:
数据如何落地
上述,我们已经写了一个最简单的缓存系统,如果此时进程挂掉了,重新启动后,内存中的数据就都没了,所以为了避免重启后数据丢失,可以将数据定时落地到磁盘中,本篇文章所介绍的内置库为:
pickle,该可可以将
python对象存储到文件中,从而保存到磁盘,这个对象可以是字典、也可以是列表,我们来看下,具体方法:
将对象保存到磁盘
使用
pickle的
dump方法,可以将对象保持到文件中,这里举一个很简单的例子:
import pickle list1 = ["name","juejin","hello"] with open("test.txt","wb") as f: pickle.dump(list1,f)
上述代码,先引入了
pickle库,而后定义了列表
list1,最后打开文件,使用
pickle.dump将列表对象保持到文件中,这里保存的是二进制,所以是
wb模式。使用
with...open方法,它可以主动在最后帮我们关闭文件句柄。
此时如我们执行脚本后,想查看一下文件,会发现是二进制格式的,例如:
将对象从磁盘中导入到内存中
上述,我们已经将对象保持到磁盘中,接下来,我们使用
pickle的
load方法,将磁盘数据导入到内存中来,这里同样举一个很简答的例子:
import pickle with open("test.txt","rb") as f: list2 = pickle.load(f) print(list2)
上述代码,还是先引入
pickle库,而后在以二进制的模式读取文件,最后通过
pickle.load方法,将数据从磁盘中导入到
list2下,接着输出
list2的值。
运行后,可以发现,该值就是我们上述落地到磁盘的对象:
将数据落地和缓存系统结合起来
我们已经将数据落地测试完毕了,如何和缓存系统结合起来呢? 很简单,我们仅需要在程序启动时,检测一下是否有该文件,若有,则直接读取数据再并入到对象中,否则创建一个新的字典就好。
而后每次有增删改操作,都将数据落地即可,这里用新增数据函数举个例子:
class cacheDB(): def __init__(self): try: with open("db.cache","rb") as f: self.cache = pickle.load(f) except Exception as e: self.cache = {} def set(self,key,value): self.cache[key] = value with open("db.cache","wb") as f: pickle.dump(self.cache,f)
上述在
cacheDB的
__init__函数中,就尝试读取本地文件
db.cache,若存在,就
load到内存中,若不存在,就创建一个新的字典。
这样的话,存储的数据就不会因为程序重启而丢失了。
如何保证并发安全
作为一个服务对开提供访问时,需要注意一下并发安全,当多个函数对一个变量进行操作的时候,很容易引起数据混乱,所以还是有必要加一下锁的,我们可以引入
threading库来完成加锁解锁操作,其加锁和解锁代码如下:
import threading lock = threading.Lock # 定义lock lock.acquire() # 加锁 lock.release() # 释放锁
我们可以将次引入到代码中,例如:
import pickle import threading lock = threading.lock class cacheDB(): def __init__(self): try: with open("db.cache","rb") as f: self.cache = pickle.load(f) except Exception as e: self.cache={} def set(self,key,value): lock.acquire() self.cache[key] = value with open("db.cache","wb") as f: pickle.dump(self.cache,f) lock.release() def main(): db = cacheDB() if __name__ == '__main__': main()