Apollo 技术文档Apollo 技术文档
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
  • MMORPG 架构 QA

Q60: 如何设计定时器系统?

核心结论

定时器系统不是“到点回调”这么简单,它本质上是在大量延迟任务之间做时间调度。

真正需要先明确的是:

  • 追求的是精度还是吞吐
  • 定时器数量级有多大
  • 回调执行是否允许阻塞主循环
  • 取消和重复调度如何处理

如果这些边界不清楚,定时器很快会变成线上抖动和性能问题的来源。

一、定时器系统真正负责什么

常见用途包括:

  • 技能 CD
  • Buff 周期触发
  • 连接超时
  • 副本倒计时
  • 定期任务

这意味着定时器系统服务的是很多上层模块,所以它必须足够稳定。

二、先区分几类定时器

1. 一次性定时器

触发一次后结束,例如:

  • 超时检测
  • 延迟执行

2. 重复定时器

按固定间隔重复执行,例如:

  • 心跳检查
  • 周期 Buff

3. 逻辑帧定时器

按游戏 tick 推进,而不是按墙钟时间触发。

这在需要与战斗、技能、状态机对齐时很常见。

三、时间精度和性能一定要权衡

不是所有定时器都需要毫秒级精确。

例如:

  • 技能 CD 和战斗事件可能需要更细粒度
  • 日常清理、离线回收则完全不需要

如果所有定时器都用同一套高精度结构,成本会很高。

四、常见数据结构怎么选

1. 最小堆

适合:

  • 中等数量
  • 需要较高精度

优点是语义清晰,缺点是插入和删除都不是常数级。

2. 时间轮

适合:

  • 定时器数量大
  • 精度要求相对可控

很多在线系统最终会选择时间轮或分层时间轮来承载大量定时任务。

没有绝对最好,关键是看数量级和精度需求。

五、回调执行不能直接把调度器拖死

定时器系统最常见的实际问题之一,不是时间不准,而是回调太重。

更稳妥的做法通常是:

  • 调度器只负责发现到期任务
  • 实际回调交给逻辑线程或任务队列

否则一个慢回调就会拖延后面所有定时器。

六、取消和重复触发要特别小心

定时器经常会遇到:

  • 回调前被取消
  • 回调执行时再次注册
  • 对象已销毁但定时器还在

所以定时器系统必须有明确的生命周期约束和失效检查。

七、工程上更稳妥的设计

常见做法是:

  • 按用途拆不同精度层级
  • 调度结构和执行结构分离
  • 定时器绑定拥有者或上下文
  • 取消采用懒删除或失效标记

这样数量、精度和安全性更容易平衡。

八、常见误区

1. 定时器越精确越好

不对。很多任务根本不值得为极高精度付出高昂成本。

2. 定时器到点直接执行回调最简单

简单,但很容易阻塞整个调度链。

3. 一个全局定时器管理器就够了

规模一大后,按用途分层往往更合理。

参考资料

  • 时间轮、最小堆和大规模定时调度相关资料
在 GitHub 上编辑此页
最后更新: 3/20/26, 6:06 AM
贡献者: cuihairu