需求:
策略类游戏中,后台自动实时结算战斗等延时事件。
特征:用户提交延时事件,后台需要在延时事件时间到时立刻执行事件。
分析:
一:扫描策略
(1) 时间步长,查找范围(lastTime, lastTime + stepTime], 通过控制stepTime大小来限制数据量。
优点: 用时间戳当边界,简单易实现
缺点: 当延时事件稀疏时,经常会出现空数据,必须一步一步的轮询,性能低。
(2) limit限制,查找范围(lastTime, stopTime] limit size,通过控制limit大小来限制数据量。
优点: 每次查询有效率高,只要有数据就可以立即获取。
缺点: 用limit之后,就会出现时间戳分页边界问题。
二:问题总结(选择扫描策略:limit限制):
(1)轮询事件和注册延时事件线程不同步问题(多线程顺序不确定性、网络不稳定)
a、在now时刻,程序准备注册延时事件发生时间为now + delay
b、轮询线程轮询(tiem0, now + advance], advance为提前获取事件的时间,如果advance为0,表示只查询已经发生的事件。
c、将发生时间为now + delay的事件写入数据库
如果now + advance >= now + delay,即事件延时的时间小于轮询提前的时间,则会出现此事件丢失的问题。
解决方法:
a、保证advance <= 事件最小delay,同时写延时事件到数据库时,不用“set time=时间戳”的形式,而是用“set time=now() + delay”的形式,就可以忽略从java程序到写入数据库的时间误差。
b、增加自增字段id,多查询一次丢失事件:time <= now + advance && id > 已轮询的最大id
(2)limit时间戳分页边界问题
例如:有如下延时事件:
时间戳 事件
1 1
2 2
3 3
4 4
5 5
5 6
5 7
5 8
5 9
5 10
当查询时间戳在范围(0,5]内limit 8时,会检索得到事件1-8,但是事件9-10的时间戳也是5,故如果下次查找范围为(5,10]时,就会丢失事件9-10.
解决方法:
a、用java实现边界去重
查询(0,5]后,保留第5毫秒的所有事件id,接下来继续查询[5, 10]的事件,将两个查询中第5毫秒的事件做去重。
这样做有一个问题,如果第5毫秒的事件总数>= limit, 则取到第5毫秒时,每次获得的都是第5毫秒的事件,然后去重,出现死循环。
解决这个问题的方法的是主查询继续查询(5,10],另起一条sql查询第5毫秒的事件然后去重。
b、用自增字段id做边界
执行查找(5, 10] or (time=5 && id > 第5毫秒中上次查询的最大id) order by time, id
也可以将边界查找用另一个sql实现,变成两条sql:
select * from table where time > lastTime && time <= stopTime
select * from table where time = lastTime && id > 上次查询结果中时间戳为lastTime的事件最大id
c、将时间戳变成唯一id,即将时间戳 + 其他信息 -> 组合(各占多少位)到一个long型字段中做唯一时间有序id
分享到:
相关推荐
接口,事件,委托,驱动监听 1.面向接口的驱动监听 2.面向委托的驱动监听 3.事件驱动监听 4.事件轮询 5.事件异步轮询
init.c轮询注册事件init.c轮询注册事件init.c轮询注册事件init.c轮询注册事件
蓝牙标准使用的循环轮询调度方案严重影响了系统的性能,针对这个问题提出了一 种公平而有效的动态轮询方案 双令牌的动态轮询方案(DTDPS)。此方案有两个重要特点 :一 是采用随机次序的访问方式,解决从设备之间的不公平...
概括事件轮询机制:分为六个阶段 1.timers 定时器阶段 计时和执行到点的定时器回调函数 2.pending callbacks 某些系统操作(例如TCP错误类型) 3.idle,prepare 4.poll轮询阶段(轮询队列) 如果轮询队列不为空,...
S7-200SMART_modbusRTU轮询程序(读轮询+写优先)附使用说明
图片轮询查看
单片机 程序架构 时间片轮询.
松下plc 轮询 标准 程序 程式,基于松下plc做的485通讯和几台其他设备通信
主要介绍了c# 实现轮询算法实例代码的相关资料,这里附有实例代码,具有一定的参考价值,需要的朋友可以参考下
S7-200SMART PLC进行MODBUS通信轮询卡死时重新开启轮询的具体方法演示
对NodeJs的事情轮询机造一孔之见。查阅了些许材料后,总算掀开了其神奇的里纱。下面这篇文章主要介绍了Node.JS中事件轮询(Event Loop)的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
一种有效的基于优先级的无线局域网轮询方案
8通道输入,1通道输出,采取请求应答方式,对8通道输入进行仲裁,采用公平轮询机制;
基于mosquitto源码新增轮询事件
Ajax轮询,Ajax长轮询和websocket.docx
本文实例为大家分享了Android实现轮询的方式,供大家参考,具体内容如下 1.通过rxjava实现(代码中使用了Lambda表达式) private static final int PERIOD = 10 * 1000; private static final int DELAY = 100; ...
本程序采用文件的形式,按照设定轮询时间对数据进行轮询显示
zencart不跳转账号轮询
vb6 modbus 进行轮询读取 接收数据长度正确后再轮询 并将接收数据依次写入三个textbox中