当前位置: 首页 > news >正文

【Rust】时间轮的数据结构于设计模式

概念来源

  • 源自“时间轮/定时轮”(Timing Wheel) 的数据结构,最经典的是 Hashed/Hierarchical Timing Wheels(1987 年提出),此后被 Linux 内核、Netty、Kafka 等广泛采用,用于高性能定时器管理。

工作原理

  • 将时间离散化为固定步长的“槽”(slot),以环形数组表示当前层的时间跨度。每次 tick,指针前进一个槽,只处理当前槽中的定时器。
  • 对超出当前层跨度的定时器,放到更高层(更大步长)的槽;随着指针循环,定时器逐级“下沉”到更精细的一层,直到到期执行。
  • 你仓库里的实现就是多层时间轮:L1~L5 层分别对应 100ms/1s/1min/1h/1d 步长,见 crates/focus-rs/src/slot/timer.rs:166 和 advance_time_wheel 逻辑 crates/focus-rs/src/slot/timer.rs:520。每次只清“当前槽位”的定时器,见 take_current_slot_timers crates/focus-rs/src/slot/timer.rs:199。短时(<1s)用一个小堆/有序结构处理,见 process_short_timers crates/focus-rs/src/slot/timer.rs:466。

为什么用“槽”

  • 插入/删除近似 O(1):定时器加入对应槽位,tick 时只处理当前槽,避免对全量定时器做 O(n) 扫描或 O(log n) 堆操作。
  • 批量处理友好:同一时间段到期的定时器集中在同一槽,tick 触发时成批拉取执行,降低锁竞争和调度开销。
  • 可扩展性强:层级化后,支持从毫秒到天的宽时间范围,且每个 tick 的工作量与当前槽内的计数成正比,而不是与定时器总数成正比。
  • 抖动可控:粒度由槽步长决定,可在“精度 vs 性能/内存”之间调参;你们将 <1s 交给短时队列,>=1s 用时间轮,兼顾精度与效率。
  • 简化并发:槽是天然的分桶,减少全局结构上的热锁;你们代码中还将短时/长时映射分离,进一步降低争用。

相对其他方案的优势/权衡

  • 相比最小堆/优先队列:插入 O(1) vs O(log n),每 tick 无需堆顶比较/调整;但时间轮存在“步长”精度限制,需要权衡 tick 和内存占用。
  • 相比纯有序表:不需要每 tick 全表扫描;但取消/重置时要注意“从槽中即时移除”(我们已在 cancel/reset 中补上移除,避免槽内残留导致同 ID 冲突)。

与你们实现的映射

  • 槽结构与操作:
    • 层与槽:crates/focus-rs/src/slot/timer.rs:166(TimeWheelLevel)
    • 取当前槽定时器:crates/focus-rs/src/slot/timer.rs:199
    • 推进并级联:crates/focus-rs/src/slot/timer.rs:520
  • 短时定时器(<1s):
    • 处理:crates/focus-rs/src/slot/timer.rs:466
  • 我们新增的即时清理(避免槽内残留):
    • 从槽位移除:crates/focus-rs/src/slot/timer.rs:221
    • 取消清槽:crates/focus-rs/src/slot/timer.rs:867
    • 重置清槽:crates/focus-rs/src/slot/timer.rs:932
  • ----------
  • 层级时间轮示意(含“槽”/slot)

L4: 天(1天/槽, 30槽)
[ 指针→ ] [ 0 ][ 1 ][ 2 ] ... [ 29 ]
↑ T4=3天 放在 L4 +3 槽

L3: 小时(1小时/槽, 24槽)
[ 指针→ ] [ 0 ][ 1 ][ 2 ] ... [ 23 ]
↑ T3=5小时 放在 L3 +5 槽

L2: 分钟(1分钟/槽, 60槽)
[ 指针→ ] [ 0 ][ 1 ][ 2 ] ... [ 59 ]
↑ T2=3分钟 放在 L2 +3 槽

L1: 秒(1秒/槽, 60槽)
[ 指针→ ] [ 0 ][ 1 ][ 2 ] ... [ 59 ]
↑ T1=7秒 放在 L1 +7 槽

L0: 毫秒(100ms/槽, 10槽)
[ 指针→ ] [ 0 ][ 1 ] ... [ 9 ]
(<1s 的短时定时器不入轮,走短时队列)

  • 运行流程(简化)

    • 新定时器加入时,根据剩余时间选择层级和槽位:
      • <1s → 短时队列(按到期时间排序,独立处理)
      • ≤60s → L1(秒级槽)
      • ≤60min → L2(分钟级槽)
      • ≤24h → L3(小时级槽)
      • ≤30d → L4(天级槽)
    • 每个 tick:
      • 处理短时队列中到期项
      • 低层(L0→L4)按顺序推进当前槽位指针,仅取“当前槽”的定时器触发
      • 若某层转了一圈(指针回到0),就把上层(更大粒度)的定时器根据精确剩余时间“下沉”到本层合适的槽(级联/下沉),等待后续更精细的触发
  • 示例(与你日志一致)

    • 6.94s → L1 +7 槽;70s → L2 +2 槽(先挂分钟级,等 L1 多圈后再下沉)
    • 339ms → 短时队列(不入轮),到时直接触发
    • 触发闭环:触发 → 激活下一段 → 立刻按剩余时长重新入轮(或入短时队列)
  • 直观好处

    • 每次 tick 只处理“当前槽”,近似 O(1),不用全量扫描或堆调整
    • 到期集中批处理,锁竞争小,可扩展到大量定时器
    • 多层粒度兼顾“精度与性能”:短时精确,长时高效
http://www.dtcms.com/a/581367.html

相关文章:

  • 解决cryptography库报错【DLL load failed while importing _rust】
  • JASP:一款免费开源的统计软件,SPSS替代产品
  • 【JS Utils】Vue2 自定义计算属性 (兼容 uniapp 和 Vue 2.7 以前版本)
  • React 16
  • 东莞网站建设技术支持南京网站建设 零云建站
  • wordpress通知站点360搜索品牌建设与管理提案
  • Python实现手写数字识别
  • 零成本体验云计算!阿贝云免费服务器深度测评
  • 如何在Mac上同步iPhone短信
  • 网站建设好后有些什么资料软件工程月薪一般多少
  • Fastapi 进阶一:Fastapi依赖注入机制详解
  • Java实用面试经验:接口编程概念与技巧总结
  • 在VMWare上搭建Flume集群
  • vue_day04
  • 深入浅出 SPA/MPA
  • 怎么增加网站的关键词库个人网站申请空间
  • (已发25年8月华为云、51CTO)数组编程:编程的基础数据结构!
  • 北京网站制作设计哪个公司好网站开发人员结构配比
  • 面对未来:企业决策与适应力
  • bat 批处理实现 FFmpeg 命令压缩 MP4
  • openEuler 云原生实战:部署高性能 Redis 集群与压测分析
  • 机器学习-逻辑回归与二分类
  • 老玩家流失?基于数据驱动的游戏用户流失分析与干预策略
  • 做网站的公司名字北京注册网站
  • 如何用c 做网站hao123从网上开始
  • ThinkPHP 8 多应用模式下如何隐藏路由中的应用名
  • [SEO]网站不收录的原因及解决方法有哪些
  • conda以及Jupyter notebook的使用
  • 告别手动录入:文档抽取技术如何让RPA处理非结构化数据?
  • MIT-数字棋盘和数字三角形