






















👉 时间轮(Timing Wheel) 是:
里的核心算法之一,属于**“看似基础,实则是对抽象极好的应用”**的内容。
—— 为什么它是 O(1) 的定时器神器?
先从一个真实问题说起。
最直观写法:
List<Timer> timers;
foreach (var t in timers)
{
if (Time.time >= t.TriggerTime)
t.Execute();
}
❌ 问题是什么?
| 方案 | 数据结构 | 插入 | 触发 | 问题 |
|---|---|---|---|---|
👉 有没有 O(1) 插入 + O(1) 触发?
答案是:时间轮
用“时间槽”代替“时间点”,
把未来的任务提前放进对应的槽里,
时间走到哪,就只处理那个槽。
假设:
slotIndex = (currentIndex + delay) % slotCount
= (2 + 5) % 8
= 7
👉 把任务放进 Slot 7

时间轮用空间换时间,把“排序问题”变成“索引问题”
⚠️ 问题来了:
slotCount * tickDuration
❌ 单层时间轮不够
| 层级 | 现实 | 槽数 |
|---|---|---|

public class TimerTask
{
public int RemainingRounds;
public Action Callback;
}
public class TimeWheel
{
private readonly List<TimerTask>[] slots;
private int currentIndex;
public TimeWheel(int slotCount)
{
slots = new List<TimerTask>[slotCount];
for (int i = 0; i < slotCount; i++)
slots[i] = new List<TimerTask>();
}
public void AddTask(int delay, Action callback)
{
int index = (currentIndex + delay) % slots.Length;
int rounds = delay / slots.Length;
slots[index].Add(new TimerTask
{
RemainingRounds = rounds,
Callback = callback
});
}
public void Tick()
{
var list = slots[currentIndex];
for (int i = list.Count - 1; i >= 0; i--)
{
var task = list[i];
if (task.RemainingRounds <= 0)
{
task.Callback();
list.RemoveAt(i);
}
else
{
task.RemainingRounds--;
}
}
currentIndex = (currentIndex + 1) % slots.Length;
}
}
TimeWheel wheel = new TimeWheel(60);
void Start()
{
wheel.AddTask(5, () => Debug.Log("5 秒后执行"));
}
void Update()
{
if (Time.frameCount % 60 == 0)
wheel.Tick();
}
| 维度 | Coroutine | 时间轮 |
|---|---|---|
👉 服务器 / 大规模定时任务:时间轮完胜
❌ Tick 精度过小 → 槽爆炸
❌ Tick 精度过大 → 任务延迟
❌ 忘记多层轮 → 最大延迟不够
❌ List 未反向遍历 → Remove 崩
❌ 回调中 AddTask → 注意线程安全
时间轮不是“更快的排序”,
而是“直接取消排序需求”的时间结构设计。
因为通过时间取模直接定位槽位,不需要排序。
堆依赖排序,时间轮依赖索引。
slotCount × tickDuration
大量定时任务下,堆的 log n 成本不可控。
技能 CD、BUFF、延迟事件、网络超时。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。