关于定时器的封装
为什么要封装定时器?
- skynet只提供定时器注册回调,缺少传参,注销,延伸等等常用方法。
实现思路
一开始尝试用分配定时器id的方式实现,这种方式要考虑id重用的情况,虽然说int64
走一个轮回要很久,但是这种情况还是要处理,走了一个轮回后,就有可能前面的id还被占用着,后续的id分配效率会降低。这种实现方式不是很稳定可靠。
后续想了一下还是用面向对象的思想,因为前一种方式无非是timer模块用一个map对应id映射定时器信息表,注册好了返回一个id,供使用者做后续注销,延期,既然返回id是返回,为什么不直接返回table呢,反正返回的也是table的引用,并没有增加什么开销,感觉分配id的操作有点画蛇添足了。
还是用面向对象思想,定时器实例提供创建定时器, 取消定时器,延长定时器等等方法。
定时器实例可以设置定时回调几次或者循环调用。后续可以继续实现按时间节点触发的定时器,比如每天上午8点,每周一零点。
特殊处理
通常注册一个定时器立马调用skynet.timeout,但是如果你的定时器需要取消,我觉得这样并不好,特别是你注册的时间较长,又会注销,过程中又触发注册很频繁的话,这样会浪费掉很多内存,因为skynet注册一个定时器就会占用一个lua携程直到定时器触发回调才释放。如果你注册触发时间为1天,那么会积压1天内注册的定时器。所以我没有直接调用skynet.timeout,而是用一个间隔60秒的check循环,如果中途注销了,循环就结束了,这样非常有效的解决了这个问题,虽然多一些定时器注册回调,但是换来了稳定性,使用者不用担心有内存暴涨的风险。
使用方式
创建定时器
timer:new()
3个必传参数
expire
回调时间,保留skynet.time_out的100等于1秒。
timer
触发次数,0次表示循环触发。
callback
回调函数。后面省略传参是回调函数的参数。
取消定时器
timeobj:cancel()
延长定时器
timeobj:extend(ex_expire)
参数
ex_expire
延长时间,如果创建定时器的时间为5秒,创建时间为:8:10:30,在定时器触发之前调用 timeobj:extend(100),定时器会再8:10:36秒触发,在定时器触发之后调用无效。