棋牌游戏定时器模块设计

棋牌游戏定时器模块设计

最近在研究棋牌游戏,想在今年上半年出一款本地麻将。github上down了几个麻将的模块走读了下,基本上可以做麻将的AI,算听,记番功能,用JNA调用了下,很nice。
算法搞定以后就是后台了,之前也接触过几个开源的游戏后台,这些开源后台其实就是搭个架子,里面的模块都没有,还需要自己垒。
我列了下棋牌后台的两个最重要的模块:
1.定时服务器
棋牌游戏里有太多的定时任务了,特别是出牌倒计时,有1000个桌子就要有1000个定时任务并发。

2.网络连接管理
上线了,掉线了,离线了,换终端了,需要重连,这些都需要专门的模块管理

当然还有数据库、异步调度、消息队列、线程池、序列化等等这些基础模块

今天只说定时器模块
现在一台服务器并发个几万桌游戏都很正常,定时任务的并发至少在几万以上。 我们广电少点吧,好歹也要准备个几千个并发能力。
很明显单纯的多线程肯定是不行的。
搜了下,都不合适,总觉得不够优化,那只能自己设计了

特点分析
1.并发高(这是肯定要concurrent并行容器了)
2.任务执行有先后次序(有点像队列)
3.只执行现在时刻的到期任务(貌似读区间和写区间是分开的,不用锁了?)
4.我理想的定时器要能记录任何时间点的任务

解析
开始想用hashmap,但是在读的时候,需要对任务执行时刻排序,为什么不能在写任务的时候就排好呢?数据结构肯定是队列无疑。
程序应该是这样的,a一条任务队列,很多游戏线程会往队列里按时间顺序插入任务。b定时服务主线程1ms轮询一次队列中第一个任务,如果到期,取出执行。
用什么数据结构呢ConcurrentSkipList ,插入拥有O(logN)复杂度,删除复杂度是O(1)可以说相当快了。

优化
1.时间轴分段?棋牌大多数倒计时都是在当前时刻15秒时(看你的游戏规则),插入时间点过于集中。
2.10条或者100条list做负载均衡? 复杂度-1和-2 。但是主线程轮询的时候需要对10个或100个数据进行排序,反而更差。

3.既然棋牌大多数都是1分钟以内的定时,我在1分钟以内的定时用轮盘实现,数量为6000,每个时间片是10ms。每个时间片使用ConcurrentHashMap实现并行插入,插入复杂度是O(1),读取复杂度也是O(1)。 当然一分钟以外的定时任务,我们可以用ConcurrentSkipList记录,并额外需要一个线程,不断把SkipList中的定时任务转移到1分钟轮盘中。
虽然多了一个线程,但是无论是空间还是时间都是非常优化的。nice!!

4.“特点3”读区间和写区间是分开的,ConcurrentSkipList第一个元素的读取复杂度是O(1)
5.(2019/02/19)优化“3”,需要多一条线程,细想还是不对,第一条线程在读取时间轮盘以后,再读取一下 ConcurrentSkipList的任务就好了,没必要两个线程。真实优化无止境啊 ,fuck!!!

总结
1 一分钟以内的定时,用6000个ConcurrentHashMap组成一个时间轮盘,每个ConcurrentHashMap存储10ms时间段的定时任务。
2 一分钟之外的定时,用ConcurrentSkipList统一存储。
3 thread1 定时轮询当前时间片的ConcurrentHashMap,并发送具体任务给对应的worker执行。然后再读取ConcurrentSkipList,并发送具体任务给对应的worker执行。
4 thread1 千万不要阻塞。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章