那些年我们一起追过的缓存写法(一)
那些年我们一起追过的缓存写法(一)在编程的世界里缓存就像是一个神奇的魔法盒子——它能让你曾经计算过的结果迅速重现避免重复劳动。从初学时的简单字典到后来复杂的多级缓存我们走过的每一步都充满了探索的乐趣。今天就让我们一起回顾那些年我们一起追过的缓存写法从最基础的概念讲起逐步走向更高级的用法。## 什么是缓存为什么需要它想象一下你每次去图书馆找一本特定的小说都要从头翻遍所有书架。这显然很浪费时间。如果你把这本书放在书桌上下次想看时直接拿起来是不是快多了这就是缓存的核心思想把频繁访问的数据存放在高速存取的地方。在程序中缓存可以- 减少重复计算提升性能- 降低数据库或API的负载- 改善用户体验## 初阶用字典实现最简单的缓存最朴素的缓存方式就是使用一个字典或哈希表来存储键值对。我们用Python写一个简单的缓存函数python# 一个简单的计算器带缓存功能def fib_with_cache(n, cache{}): 计算斐波那契数列的第n项并使用字典缓存中间结果。 if n in cache: # 如果结果已在缓存中 return cache[n] # 直接返回 if n 2: result n else: result fib_with_cache(n-1, cache) fib_with_cache(n-2, cache) cache[n] result # 将计算结果存入缓存 return result# 测试print(fib_with_cache(10)) # 输出55print(fib_with_cache(100)) # 即便计算大数也不卡顿这段代码利用了Python中默认参数只初始化一次的特性使得cache字典在多次调用间共享。它的优点是非常简单缺点也很明显缓存会无限增长而且不支持并发安全。## 中阶使用functools.lru_cache自动管理Python标准库为我们提供了更优雅的解决方案functools.lru_cache装饰器。它自动实现了**最近最少使用LRU**淘汰策略当缓存满了会移除最久未使用的数据。pythonfrom functools import lru_cachelru_cache(maxsize128) # 最多缓存128个结果def fib_lru(n): 使用lru_cache装饰的斐波那契函数。 当缓存满时自动淘汰最久未使用的条目。 if n 2: return n return fib_lru(n-1) fib_lru(n-2)# 测试print(fib_lru(10)) # 55print(fib_lru(100)) # 354224848179261915075瞬间返回print(fib_lru.cache_info()) # 查看缓存状态CacheInfo(hits?, misses?, maxsize128, currsize?)lru_cache的优点- 自动管理缓存大小- 支持统计信息命中率等- 线程安全在Python 3.8中- 可设置typedTrue区分不同类型参数但注意lru_cache仅适用于**纯函数**无副作用输出仅由输入决定并且参数必须是可哈希的。## 进阶自定义TTL生存时间缓存有时候我们需要缓存数据在特定时间后自动失效比如从数据库读取的用户信息5分钟后应该刷新。lru_cache不支持TTL我们可以自己构建一个带过期时间的缓存pythonimport timefrom functools import wrapsdef ttl_cache(ttl_seconds300, maxsize128): “” 自定义TTL缓存装饰器。 - ttl_seconds: 缓存生存时间秒 - maxsize: 最大缓存条目数 “” def decorator(func): cache {} # 使用有序字典维护访问顺序便于LRU淘汰 from collections import OrderedDict wraps(func) def wrapper(*args, **kwargs): # 生成缓存键注意这里简化了kwargs的处理 key (args, tuple(sorted(kwargs.items()))) now time.time() # 检查缓存是否有效 if key in cache: value, timestamp cache[key] if now - timestamp ttl_seconds: # 缓存命中且未过期更新访问顺序 cache.move_to_end(key) return value else: # 缓存过期删除旧条目 del cache[key] # 计算新值 result func(*args, **kwargs) # 如果超出最大容量淘汰最久未使用的条目 if len(cache) maxsize: cache.popitem(lastFalse) # 移除最早访问的条目 cache[key] (result, now) return result return wrapper return decorator# 使用示例ttl_cache(ttl_seconds10, maxsize5)def get_user_info(user_id): “” 模拟从数据库获取用户信息耗时操作 “” print(f正在从数据库获取用户 {user_id} 的信息…“) time.sleep(2) # 模拟耗时 return {“id”: user_id, “name”: fUser_{user_id}”, “time”: time.time()}# 测试print(get_user_info(1)) # 第一次等待2秒print(get_user_info(1)) # 第二次立即返回缓存命中time.sleep(11) # 等待超过TTLprint(get_user_info(1)) # 第三次缓存过期重新计算这个自定义缓存虽然功能强大但仍有不足**不支持并发安全**、**未处理异常情况**、**键生成不够健壮**。在实际项目中建议使用成熟的第三方库如cachetools。## 高级用法多级缓存策略在大型系统中单层缓存往往不够用。常见的是**多级缓存**例如- **一级缓存**本地进程内缓存如lru_cache速度最快但容量有限- **二级缓存**分布式缓存如Redis速度较快容量大- **三级缓存**数据库或外部API速度最慢一个简化的多级缓存实现pythonimport redisfrom functools import lru_cacheclass MultiLevelCache: “” 多级缓存示例本地LRU Redis “” definit(self, local_size100, redis_clientNone): self.local_cache lru_cache(maxsizelocal_size)(self._get_from_redis) self.redis redis_client or redis.Redis(host‘localhost’, port6379, db0) def _get_from_redis(self, key): “”“从Redis获取数据如果不存在则返回None”“” return self.redis.get(key) def get(self, key): “”“获取数据先查本地缓存再查Redis”“” result self.local_cache(key) # 先查本地 if result is None: # 本地没有从数据库加载实际中需实现 result self._load_from_db(key) # 回填到Redis self.redis.set(key, result, ex300) # 5分钟过期 # 清除本地缓存强制下次重新加载 self.local_cache.cache_clear() return result defload_from_db(self, key): “”“模拟从数据库加载”“” print(f从数据库加载 {key}) return fdata{key}这种设计结合了本地缓存的快速和Redis的容量优势是生产环境中的常见模式。## 总结从最简单的字典缓存到标准库的lru_cache再到自定义TTL缓存最后到多级缓存架构我们见证了缓存写法的进化之路。每一步都体现了对性能、内存管理、并发安全的追求。关键要点1. 缓存不是银弹——需要权衡内存占用与性能提升2. 选择合适的淘汰策略LRU、LFU、TTL等3. 注意缓存的失效与更新缓存穿透、雪崩、击穿4. 生产环境中优先使用成熟库cachetools、redis-py等下期预告我们将深入探讨缓存的常见陷阱——缓存穿透、雪崩和击穿以及如何用布隆过滤器、互斥锁等技巧来应对。敬请期待—缓存的世界深似海但每一次优化都让我们离完美更近一步。希望这篇文章能帮助你回顾那些年我们一起追过的缓存写法也为未来的探索埋下种子。

相关新闻

HarmonyOS开发实战:笔友-Hamock 组件 Mock 在页面单元测试中的应用

HarmonyOS开发实战:笔友-Hamock 组件 Mock 在页面单元测试中的应用

前言 在 ArkUI 应用中,组件 Mock 是页面单元测试的关键技术。xiexin 在 oh-package.json5 中引入了 ohos/hamock 工具,用于在测试中替换真实组件,验证组件交互逻辑。 本文将以 AddPenPalPage.ets 和 CommonComponents.ets 为蓝本&#xff0…

2026/10/16 14:56:07 阅读更多 →
screen_capture_lite常见问题解答:解决跨平台捕获的8大痛点

screen_capture_lite常见问题解答:解决跨平台捕获的8大痛点

screen_capture_lite常见问题解答:解决跨平台捕获的8大痛点 【免费下载链接】screen_capture_lite cross platform screen/window capturing library 项目地址: https://gitcode.com/gh_mirrors/sc/screen_capture_lite screen_capture_lite是一款强大的跨平…

2026/10/17 8:35:04 阅读更多 →
C++项目CI/CD中静态与动态代码质量分析的整合实践

C++项目CI/CD中静态与动态代码质量分析的整合实践

1. 项目概述:为什么C项目的CI/CD必须整合代码质量分析?在C开发领域,尤其是涉及系统底层、游戏引擎、高频交易或嵌入式等对性能和稳定性要求极高的场景,代码质量从来都不是一个“锦上添花”的选项,而是项目存续的生命线…

2026/10/16 12:24:30 阅读更多 →

最新新闻

美赛B题O奖论文拆解:概率搜索模型与路径规划实战

美赛B题O奖论文拆解:概率搜索模型与路径规划实战

去年美赛B题一出,圈子里都在讨论那篇O奖论文。英文原题翻译成中文,核心是四个字:失联寻回。那篇O奖论文的标题如果直译,大概就是《从失联到寻回:某片海域的搜寻之旅》。我刻意不提具体海域名,因为做案例分析…

2026/10/19 22:05:38 阅读更多 →
多测站GNSS精密定位:Kriging插值与卡尔曼滤波实现网络RTK

多测站GNSS精密定位:Kriging插值与卡尔曼滤波实现网络RTK

很多人第一次看到“多测站 GNSS 精密定位 Kriging 卡尔曼滤波”这条链路时,第一反应都是:有必要这么复杂吗?单站差分、PPK、PPP不也能定位吗。我之前做某测试场的动态定位精度评估时也这么想,直到某次基准站距离用户站超过30km&…

2026/10/19 22:05:38 阅读更多 →
IM系统用户管理子服务架构设计与踩坑实践:从表结构到缓存策略

IM系统用户管理子服务架构设计与踩坑实践:从表结构到缓存策略

做IM系统,用户管理子服务往往是看起来最简单、坑却最多的那一块。很多人一开始会觉得,无非就是注册、登录、改个昵称、拉个好友列表,有什么好写的?但真正上手做才发现,一个IM系统里最基础的用户服务,牵扯到…

2026/10/19 22:03:35 阅读更多 →
DUT-OMRON数据集上的U-Net二值分割实战:边缘鲁棒与工业落地

DUT-OMRON数据集上的U-Net二值分割实战:边缘鲁棒与工业落地

简介:本资源是一套面向深度学习初学者与图像分割实践者的Unet多尺度分割实战项目,聚焦二值图像分割任务,特别适配DUT-OMRON数据集的端到端训练与推理需求。压缩包共2000个文件,主体为1979张PNG格式的训练/测试图像及对应mask&…

2026/10/19 22:03:35 阅读更多 →
XXE漏洞剖析:从XML外部实体注入到文件读取与SSRF防御

XXE漏洞剖析:从XML外部实体注入到文件读取与SSRF防御

大概在五年前做某次授权测试,目标系统有个不起眼的文件上传接口,响应报文里带着一段 XML 结构。当时随手改了改请求体,把实体声明换成了外部实体,结果直接把服务器上的/etc/passwd读了出来。那是我第一次真正意识到 XXE&#xff0…

2026/10/19 22:02:34 阅读更多 →
编译通过≠代码健康:C++静态检测原理与工具落地指南

编译通过≠代码健康:C++静态检测原理与工具落地指南

编译通过不等于代码健康:C静态检测到底在查什么我做C开发这些年,越来越觉得一个道理:编译器不报错,只是说你的代码符合语法和类型规则,它压根不关心你的逻辑是不是对的、指针是不是悬空的、资源有没有泄漏。很多问题要…

2026/10/19 22:02:34 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →