如何在Python中实现一个类似Redis的数据过期机制?

星静姑娘_8182

星静姑娘_8182

2026-06-14

982人浏览

原创

redis采用惰性删除与定期删除双策略:访问键时检查并删除过期key(惰性),同时每秒10次随机抽样清理(定期),兼顾内存效率与cpu开销。

如何在python中实现一个类似redis的数据过期机制?

用 threading.Timer 实现单次过期不靠谱

直接为每个 key 启动一个 threading.Timer 看似直观,但实际会快速耗尽线程资源,尤其在高频写入、大量 key 场景下极易触发 RecursionError 或内存暴涨。Timer 本质是延迟执行+销毁,无法动态调整或批量清理,也不支持 TTL 更新。

实操建议:

  • 避免对每个 key 单独建 Timer,哪怕用线程池也难控生命周期
  • 若仅需极简原型(比如测试用),可用 heapq + 单个后台线程轮询最小堆,但务必加锁保护过期检查和删除操作
  • 真正要接近 Redis 行为,必须引入“惰性删除 + 定期抽样”双策略,否则无法兼顾精度与性能

用 heapq 维护过期时间堆 + 后台线程抽样清理

核心思路是把所有带 TTL 的 key 按过期时间戳存进最小堆(heapq),后台线程定期 peek 堆顶,若已过期则 pop 并删除对应 key;同时每次 get/set 操作都顺手检查堆顶是否过期(惰性删除)。

关键细节:

  • 堆中存的是 (expire_timestamp, key) 元组,注意 timestamp 必须是绝对时间(如 time.time() + ttl_sec),不能存相对值
  • 每次 set(key, value, ex=60) 时,先从堆中移除旧的同 key 过期项(需额外维护 key → expire_timestamp 映射,否则无法精准删除)
  • 后台线程 sleep 间隔建议设为 100ms~1s,太短空转浪费 CPU,太长导致过期延迟明显
  • 抽样清理时别一次删光——Redis 默认每次只检查 20 个随机 key,你也该限制单次最多处理 min(20, len(heap))

__delitem__ 和 __getitem__ 里必须做惰性过期检查

用户调用 cache['key'] 或 del cache['key'] 时,不能假设 key 还有效。哪怕后台线程还没扫到它,也可能已超时。

python学习
python学习

Python 编程学习助手 skill,面向零基础用户。 当用户表达以下意图时触发: - 学习 Python 基础概念(变量、数据类型、循环、函数、类等) - 请求 Python 练习题或测验 - 请求审查或调试 Python 代码 - 请求 Python 项目实战指导(爬虫、数据分析、Web 开发等入门项目) - 泛化表述如"教我 Python""我想学编程""Python 怎么写""帮我学 Python" 此 skill

下载

实操要点:

  • 在 __getitem__ 开头立刻查该 key 是否在过期映射中,且 expire_timestamp ;若是,先 <code>del 再抛 KeyError
  • __delitem__ 同理:先检查是否过期,再从数据字典和过期堆中同步清理(注意堆无法高效删指定元素,所以依赖“标记失效+后续跳过”的方式更稳妥)
  • 不要在 __setitem__ 里主动触发清理——那是后台线程的事;但要确保新 TTL 覆盖旧记录,包括更新堆和映射表

用 weakref 或 __slots__ 控制内存膨胀风险

长期运行的服务里,如果 key 数量大、TTL 长短不一,过期堆和映射表本身就会成为内存瓶颈。单纯靠清理逻辑不够,得从结构上约束。

推荐做法:

  • 给缓存类加上 __slots__ = ('_data', '_expires', '_heap', '_lock'),禁用动态属性,减少单实例内存占用
  • 不用 dict 存全部 key 的过期时间,改用 weakref.WeakKeyDictionary(如果 key 是可哈希对象)或 weakref.WeakValueDictionary(如果 value 可被回收)
  • 堆中不存原始 key 对象,而存其 hash 或 id,配合外部字典做间接引用,避免循环引用阻碍 GC

过期机制真正的复杂点不在“怎么删”,而在“删不干净时怎么不让系统变慢”。堆的修复、锁粒度、GC 友好性,这些才是压测时最先暴露的问题。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

python redis

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1791

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

4704

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1749

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

27917

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3367

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3367

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1203

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

616

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2623

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习