python | 写一个简单的缓存系统

简介: python | 写一个简单的缓存系统

我们昨天已经学习了python的文件读写,今天来做一个最简单的例子,写一个最简单的缓存系统,要求:


key``value的方式保持数据,并且需要将内容中的数据落地到文件,以便下次启动的时候,将文件的内容加载进内存中来。


还是需要声明一点,本篇文章所依赖的python环境为:

image.png


代码已经放到了码上掘金以及gitee上。

这里需要注意的是在码上掘金中,由于未知原因,无法创建缓存文件,所以想测试的,可以将代码拷贝到本地执行。

码上掘金地址:

import pickle
import time
import threading
def deferFunc(func):
    def wrapper(*args):
        self = args[0]
        self.lock.acquire()
        try:
            result = func(*args)
            self.cacheKeysNum = self.cacheKeysNum + 1
            self.writeToDisk()
            return result
        finally:
            self.lock.release()
    return wrapper
class dbCache():
    def __init__(self,loadFiles):
        self.cacheFile = loadFiles
        self.lastTimes = time.time()
        self.cacheKeysNum = 0
        self.lock = threading.Lock()
        self.cacheSetting()
        try:
            with open("db.cache","rb") as f:
                self.caches = pickle.load(f)
        except Exception as e:
            print("open file errors" , e)
            self.caches = {}
    def cacheSetting(self,queueMaxKeys = 3,ageSec = 10):
        self.queueMaxKeys = queueMaxKeys
        self.ageSec = ageSec
    def writeToDisk(self):
        if self.cacheKeysNum >= self.queueMaxKeys or (time.time() - self.lastTimes) >= self.ageSec:
            with open(self.cacheFile, "wb") as f:
                pickle.dump(self.caches, f)
            self.lastTimes = time.time()
            self.cacheKeysNum = 0
    @deferFunc
    def get(self,key):
        if key in self.caches:
            return self.caches[key]
        else:
            return None
    @deferFunc
    def set(self,key,value):
        if key != "":
            self.caches[key] = value
        else:
            raise "key cannot be empty"
    def isExists(self,key):
        if key in self.caches:
            return True
        else:
            return False
    @deferFunc
    def update(self,key,value):
        if self.isExists(key):
            self.caches[key] = value
            return True
        else:
            return False
    @deferFunc
    def delete(self,key):
        if self.isExists(key):
            del self.caches[key]
            return True
        else:
            return False
def main() -> None:
    c = dbCache("db.cache")
    c.cacheSetting(queueMaxKeys=3,ageSec=3)
    c.set("name","pdudo")
    time.sleep(5)
    c.set("site","juejin")
    print(c.get("name"))
    c.delete("name")
    c.update("site","pdudo")
if __name__ == '__main__':
    main()

gitee地址: gitee.com/pdudo/golea…



项目展示


demo将分为2个部分展示,第一个部分我们会写入一些keyvalue进入到缓存系统中,而后关闭程序。


第二部分则会去获取第一个部分写入的key的名称。

第一部分main方法如下:

image.png


其中,dbCache是我们定义的类,而set是写入方法,cacheSetting设置一些基础环境变量,例如:


  • queueMaxKeys: 需要制定增删改缓存队列,类型为int,如果满了,则立即落地到磁盘中。
  • ageSec: 间隔时间,参数为秒数,若操作第一个key和操作第二个key时间大于该设置,则落地到磁盘。

set则是写入方法,参数为keyvalue

运行后,代码效果如下:

image.png

由于我们只有set,所以不会输出任何信息,上述open file error 是正常的警告信息,不用管它。

第一部分操作完毕了,我们可以修改第二部分,使用get去获取第一次存储的数据。

修改main如下:

image.png


运行后,效果如下:

image.png


由此可以验证,从磁盘读取文件并且加载进内存,没什么问题。

除此之外,该库还支持其他操作,例如:

# 定义一个缓存对象
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,可以使用如下代码:


写入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



定义一个不用落地的缓存系统

有了上述关于字典的基本操作,我们可以将其封装一下,定义为自己的操作方法,例如:

image.png


我们可以将上述方法,封装在一个class中,从而实现调用。

例如,运行之后结果为:

image.png



数据如何落地


上述,我们已经写了一个最简单的缓存系统,如果此时进程挂掉了,重新启动后,内存中的数据就都没了,所以为了避免重启后数据丢失,可以将数据定时落地到磁盘中,本篇文章所介绍的内置库为: pickle,该可可以将python对象存储到文件中,从而保存到磁盘,这个对象可以是字典、也可以是列表,我们来看下,具体方法:



将对象保存到磁盘


使用pickledump方法,可以将对象保持到文件中,这里举一个很简单的例子:

import pickle
list1 = ["name","juejin","hello"]
with open("test.txt","wb") as f:
    pickle.dump(list1,f)

上述代码,先引入了pickle库,而后定义了列表list1,最后打开文件,使用pickle.dump将列表对象保持到文件中,这里保存的是二进制,所以是wb模式。使用with...open方法,它可以主动在最后帮我们关闭文件句柄。


此时如我们执行脚本后,想查看一下文件,会发现是二进制格式的,例如:

image.png



将对象从磁盘中导入到内存中


上述,我们已经将对象保持到磁盘中,接下来,我们使用pickleload方法,将磁盘数据导入到内存中来,这里同样举一个很简答的例子:

import pickle
with open("test.txt","rb") as f:
    list2 = pickle.load(f)
print(list2)

上述代码,还是先引入pickle库,而后在以二进制的模式读取文件,最后通过pickle.load方法,将数据从磁盘中导入到list2下,接着输出list2的值。


运行后,可以发现,该值就是我们上述落地到磁盘的对象:

image.png


将数据落地和缓存系统结合起来


我们已经将数据落地测试完毕了,如何和缓存系统结合起来呢? 很简单,我们仅需要在程序启动时,检测一下是否有该文件,若有,则直接读取数据再并入到对象中,否则创建一个新的字典就好。

而后每次有增删改操作,都将数据落地即可,这里用新增数据函数举个例子:

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() # 释放锁

我们可以将次引入到代码中,例如:

image.png


这里就不做演示了。



总结


本篇文章,介绍如何写一个最简单的缓存系统,其核心点是定义了一个字典类型来保存key/value数据,并且根据相应的逻辑,使用pickleload方法保持到本地磁盘中,而后需要加载的时候再从本地文件加载到内容中即可,最后作为一个服务,应当考虑到并发安全的问题,给增删改方法加一个锁,从而避免并发问题。最后的最后,再将功能重复代码给踢出来,稍微润色一下,就差不多可以了。




相关文章
|
17天前
|
机器学习/深度学习 数据采集 供应链
使用Python实现智能食品安全追溯系统的深度学习模型
使用Python实现智能食品安全追溯系统的深度学习模型
41 4
|
6天前
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
58 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
7天前
|
机器学习/深度学习 算法 前端开发
基于Python深度学习的果蔬识别系统实现
果蔬识别系统,主要开发语言为Python,基于TensorFlow搭建ResNet卷积神经网络算法模型,通过对12种常见的果蔬('土豆', '圣女果', '大白菜', '大葱', '梨', '胡萝卜', '芒果', '苹果', '西红柿', '韭菜', '香蕉', '黄瓜')图像数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django框架搭建Web网页端可视化操作界面,以下为项目实现介绍。
18 4
基于Python深度学习的果蔬识别系统实现
|
2月前
|
机器学习/深度学习 传感器 存储
使用 Python 实现智能地震预警系统
使用 Python 实现智能地震预警系统
130 61
|
2月前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
67 15
Android 系统缓存扫描与清理方法分析
|
1月前
|
弹性计算 数据管理 数据库
从零开始构建员工管理系统:Python与SQLite3的完美结合
本文介绍如何使用Python和Tkinter构建一个图形界面的员工管理系统(EMS)。系统包括数据库设计、核心功能实现和图形用户界面创建。主要功能有查询、添加、删除员工信息及统计员工数量。通过本文,你将学会如何结合SQLite数据库进行数据管理,并使用Tkinter创建友好的用户界面。
51 2
从零开始构建员工管理系统:Python与SQLite3的完美结合
|
24天前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
垃圾识别分类系统。本系统采用Python作为主要编程语言,通过收集了5种常见的垃圾数据集('塑料', '玻璃', '纸张', '纸板', '金属'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对图像数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。然后使用Django搭建Web网页端可视化操作界面,实现用户在网页端上传一张垃圾图片识别其名称。
72 0
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
|
24天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
67 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
1月前
|
机器学习/深度学习 数据采集 存储
使用Python实现智能农业灌溉系统的深度学习模型
使用Python实现智能农业灌溉系统的深度学习模型
158 6
|
1月前
|
机器学习/深度学习 数据采集 算法框架/工具
使用Python实现智能生态系统监测与保护的深度学习模型
使用Python实现智能生态系统监测与保护的深度学习模型
97 4