定时器应用
- 心跳检测
- 技能冷却
- 倒计时
- 定时任务
- 超时机制
概述
服务器定时器两种实现:
- 网络时间和事件时间在一个线程中处理
- epoll_wait时timeout设成最近一个定时器的时间
- 网络时间和事件时间在不同线程中处理
- 多开一个线程专门处理定时任务,没任务时调用sleep
接口设计
// 初始化定时器
void init_timer();
// 添加定时器
Node* add_timer(int expire, callback cb);
// 删除定时器
bool del_timer(Node* node);
// 找到最近要发⽣的定时任务
Node* find_nearest_timer();
// 更新检测定时器
void update_timer();
// 清除定时器
void clear_timer();
数据结构方案
要求能快速查找最小节点
- 最小堆 O(logn)
- 红黑树 O (logn)
- 时间轮 O(1)
红黑树
时间(key)相同怎么处理?
- 加一个很小的offset
- key相等的用链表接上
- 让红黑树的实现不要求key相等,每次总是把key相等的插在原来的右子节点
最小堆
完全平衡二叉树,比红黑树更快,内存占用小,缺点是不能快速查找/删除任意元素
时间轮
减少无效检测,每次查找的时候找到的总是有效的事件(类似哈希表,以触发时间为key)
单层时间轮
数组长度必须大于最长的定时
每个格子代表一个单位时间(可以是秒,或者五秒,十秒…)
每隔单位时间,把指针往后移动一格,处理当前各自里所有事件
多层级时间轮
适用于不同定时任务之间定时长度相差很大的情况(比如一个几秒触发一次,一个每个月触发一次),作用是节省内存
把第一层想成时钟的秒针,第二次是分针,第三层是时针…
只有一分钟以内的任务会被放在第一层,大于等于一分钟小于一小时的被放在第二层…
每次第n层的指针移动,会把当前各自里的所有事件移动到下面几层(重新映射)
参考资料
零声教育c/c++ linux后台开发 3.2.3