java实现时间轮定时器_基于侵入式链表的时间轮定时器实现
游戏服务器一般都会需要这样一种功能 – 在某个确定的时间点干某件特定的事情,例如:某个排行需要在每月第一天进行结算,某个比赛需要在下周六中午12:00准时通知服务器所有玩家比赛开始……当然,这种功能不局限于游戏服务器,其他类型服务器或多或少也有包含。我们称之这个功能为定时器功能或者定时器组件。
这里实现了一种用C++模板机制实现的秒级(比较容易改写成毫秒级)定时器,核心算法使用的是时间轮(Timing-Wheel),辅助数据结构使用的是侵入式链表(Intrusive-List)。首先简单介绍一些基本概念。
侵入式链表(Intrusive-List)
最典型的Intrusive-List例子应该就是linux内核中使用的链表了,它的优点是用户知道自己在表中的位置,删除比较方便,且用户自己管理数据块,这个数据块可以被多个链表同时共享(注意这是一个很重要的特性,相比非侵入式链表节约了不少空间),这种数据结构在redis,nginx代码中广泛使用。
相对应的,非侵入式链表(Non-intrusive-list)的例子就是std::list了,被使用在各大软件与应用中,易用,稳定,用户群里大基本任何关于它的问题都可以google到,当然这里说的Non-intrusive-list不单单只是指std::list,只是std::list占去了Non-intrusive-list至少90%的“市场份额”。
一些比较好的关于链表资料:
时间轮(Timing-Wheel)
对于Timing-Wheel的基本理解就像老式钟表,一个圆盘,上面很多刻度,外加刻度针。每次Tick,轮盘转动(根据物理相对运动,也可以理解成刻度针摆动),这时指针指向新的刻度标签,这个刻度标签上有任何过期定时器那么则进行处理,定期进行下一次Tick,处理下一个刻度标签上的事件……
本文的实现
游戏服务器一般来说不需要很精确的计时(端游上需要毫秒级,一些技能的吟唱是需要毫秒级支持的),特别手游服务器一般精确到秒级即可,所以对于Timing-Wheel的N取值为60即可(1分钟60秒,每秒对应一个轮)。我们采用每个轮子上挂接顺序链表的方式进行定时器存储,这样的话在轮询时只用判断表头是否过期即可。
对于插入行为,我们根据定时器过期时间(expireTm)对N值进行求余hash,从而找到对应的轮,将其插入顺序链表。
对于轮的转动,原则上以秒为单位进行指针移动。
问题与解决
问题1:若定时器过期处理函数(func)耗时过长,导致精度下降,如何处理?
建议是在func中不要放过重的逻辑,如果无法避免重逻辑,可以使用线程解决。但是使用线程会使开发同步性的成本就会增加,也会增加维护的复杂度,所以这是一个取舍过程,本文中的实现无法完全避免这个问题。
问题2:一个过期处理函数(func)耗时几秒,已经导致了精确严重下降,如何处理?
本文实现一个简单的追赶机制,我们在处理定时器过期线程(滴答线程)将每次滴答(Tick)时间默认设置为200ms,并且记录当前的时间指针位置(secStep),当发生了一个很耗时的func,我们会发现当前时间(curTm)大于secStep,那么我将secStep++,直到curTm==secStep我们就不做任何移动当前secStep的操作,让其自动随时间移动,这样在1秒的时间内可以大约追赶4秒误差。
问题3:定时器是否线程安全?
是,粗暴的使用线程锁。
问题4:定时器内存管理是怎么样的?
内存会对定时器事件(timerEvent),进行new/delete(可以优化为高效的内存池模式),无需用户进行额外的内存操作。
java实现时间轮定时器_基于侵入式链表的时间轮定时器实现相关推荐
- 侵入式与非侵入式链表
侵入式与非侵入式链表 非侵入式链表 非侵入式链表中数据保存在节点中,结点链接域存的是下一个结点的内存首地址 template<typename T> struct ListNode {Li ...
- java线程轮询_基于springboot实现轮询线程自动执行任务
本文使用: Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务.使用这种方式可以让你的程序按照某一个频度执行, 但不能在指定 ...
- java 长轮询_基于springboot 长轮询的实现操作
springboot 长轮询实现 基于 @EnableAsync , @Sync @SpringBootApplication @EnableAsync public class DemoApplic ...
- java象棋游戏用户特点_基于Java Swing的《中国象棋》游戏的设计与实现
60 开发经验 3基金项目: 江西省自然科学基金资助项目(编号: 0411046); 江西省高性能计算技术重点实验室资助基金项目(No. JXHC20052003) ). 基于 Java Swing ...
- java契约_基于契约式设计的Java编译器实现
上海交通大学硕士学位论文 基于契约式设计的Java编译器实现 学校:上海交通大学 院系:软件学院 专业:计算机软件与理论 班级:B0403791 学号:1040379006 作者姓名:张嘉铭 指导教师 ...
- stm32单片机实现多个闹钟_基于STM32F103系列单片机的11个定时器解析
STM32F103系列的单片机一共有11个定时器,其中: 2个高级定时器 4个普通定时器 2个基本定时器 2个看门狗定时器 1个系统嘀嗒定时器 除去看门狗定时器和系统滴答定时器的八个定时器列表; 8个 ...
- pde与波长 sipm 关系_基于SiPM和TCMPC的时间分辨拉曼散射测量技术研究
引用本文 苗泉龙, 代雷, 李佰成, 赵天琦, 梁琨, 杨茹, 韩德俊. 基于SiPM和TCMPC的时间分辨拉曼散射测量技术研究[J]. 光谱学与光谱分析, 2018,38(5): 1444-1450 ...
- mysql中时间处理函数_基于mysql时间处理函数的应用详解
DAYOFWEEK(date) 返回日期date的星期索引(1=星期天,2=星期一, --7=星期六).这些索引值对应于ODBC标准. mysql> select DAYOFWEEK('1998 ...
- java 非侵入式_非侵入式设计 和侵入式设计 意思?
非侵入式系介绍DI用语,我得理解是两个组件(类,接口)之间,比较独立,不深入到另一个类内部,哪位大虾能点拨一二? 关于"侵入式"和"非侵入式"设计 有读者讲&q ...
- vuejs 轮播_如何在VueJS中设计和构建轮播功能
vuejs 轮播 by Fabian Hinsenkamp 由Fabian Hinsenkamp设计 A carousel, slideshow, or slider - however you ca ...
最新文章
- ArrayList用法说明
- Scala与Java差异(五)之Map与Tuple
- mysql 自连接 树形_自连接表的相关问题(树形结构)
- Eclipse 常用快捷键收集
- 生成式建模“回归”信息抽取
- 转:js中arguments详解
- 7.Java反射面试题
- Multisim简体中文汉化包下载安装指南
- Python学习笔记——python基础之python中for......else......的使用
- 每周全球科技十大新闻(2021.2.1-2.7)
- 面试 11、知识拓展
- 在线Base64编码/解码
- Python制作词云视频,通过词云图来看小姐姐跳舞
- python之bug0:selenium使用新版edge(chrome内核) 导致的webdriver.Edge 运行报错
- 修改mysql8.0中数据库的名字
- 阿里巴巴十年Java架构师分享,会了这个知识点的人都去BAT了
- Conflux项目进度报告 十月第一期
- linux cadaver 命令,screen命令用法与cadaver
- 打开PS出现Unable to continue because of a hardware quo
- 设置vlan虚拟局域网