利用Python编写一个简单的缓存系统
作者:真的不能告诉你我的名字 发布时间:2021-08-15 02:55:39
我们昨天已经学习了python
的文件读写,今天来做一个最简单的例子,写一个最简单的缓存系统,要求:
以key``value
的方式保持数据,并且需要将内容中的数据落地到文件,以便下次启动的时候,将文件的内容加载进内存中来。
还是需要声明一点,本篇文章所依赖的python
环境为:
代码已经放到了gitee上,gitee
地址: gitee.com/pdudo/golearn/blob/master/python/cacheDB/main.py
项目展示
该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()
这里就不做演示了。
来源:https://juejin.cn/post/7223441307960049725


猜你喜欢
- 本文实例讲述了Python Web框架之Django框架Model基础。分享给大家供大家参考,具体如下:model是关于你的数据的单一的,确
- 很多时候我们需要对数字进行格式化,比如位数不足前面加0补足。用PHP可以很轻易实现,因为PHP自带了相关功能的函数。<?php &nb
- 前言在数据分析中,分组聚合二者缺一不可。对数据聚合(求和、平均值等)通常是不可避免的。pd.agg()很方便进行聚合操作。1. 创建Data
- IP合法性校验是开发中非常常用的,看起来很简单的判断,作用确很大,写起来比较容易出错,今天我们来总结一下,看一下3种常用的IP地址合法性校验
- 第一种情况是返回的游标是某个具体的表或视图的数据,如:SQL-Code:CREATE OR REPLACE P
- 本文实例讲述了js+php实现静态页面实时调用用户登陆状态的方法。分享给大家供大家参考。具体分析如下:在程序开发中,经常会把页面做成html
- pom.xml文件中引入如下内容<dependency><groupId>com.github.ulisesbocc
- MFCC梅尔倒谱系数(Mel-scaleFrequency Cepstral Coefficients,简称MFCC)。MFCC通常有以下之
- 在上篇博客中,提到了对一个脚本进行的多次优化。当时以为已经优化得差不多了,但是当测试人员测试时,我才发现,踩到了Python的一个大坑。在上
- 手里有个老项目是基于element admin框架下的,之前写的时候没考虑到要打包成桌面端,后期需要打包成客户端,然后就开始了一些列版本操作
- 起源:.clearfix:after {visibility: hidden;display: block;font-size: 0;con
- 本文主要研究的是Python编程删除服务器文件,具体实现 代码如下。实例1#coding:utf-8import paramiko"
- 1 StreamingHttpResponse下载StreamingHttpResponse(streaming_content):流式相应
- 说明1、Matplotlib函数可以绘制图形,使用plot函数绘制曲线。2、需要将200个点的x坐标和Y坐标分别以序列的形式输入plot函数
- 一个可能你似曾相识的场景阅读内容包含大量英文的 PPT、Word、Excel 或者记事本时,由于英语不熟悉,为了流利地阅读,需要打开浏览器进
- 如果说亲密性原则是对元素的归类组合,是将元素之间逻辑理解上的差异在视觉上表现出来,是属于信息分类的话,那么对齐原则即是在视觉上串起这些差异化
- 需求当需要同时ping/telnet多个ip时,可以通过引入ping包/telnet包实现,也可以通过go调用cmd命令实现,不过后者调用效
- 本文实例讲述了Python自动发送邮件的方法。分享给大家供大家参考,具体如下:python发邮件需要掌握两个模块的用法,smtplib和em
- 目录一、使用说明二、代码分析1. 功能函数2. 回调函数3. 线程生成函数4. 效果展示写在最后在科研学习的过程中,我们难免需要查询相关的文
- 为什么要使用滤波消除图像中的噪声成分叫作图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频段是很常见的,而在较高频段,感