【C#】 定时器设计过程的记录
在Windows 系统上 C# 常用定时器有三种,而最高进度的定时器误差 58ms 则个误差数字无法应用 16ms 级别的定时轮询,但还有另外的高精度定时器,这不是还有其他方法吗,对有的,空转也指的是直接让线程一只空转,设置休眠线程的间隔来达到同样的目的,但这样就无法在休眠的时间内执行其他事情,弊端还很多;
另外的方式,也有框架实现的,误差虽然有很高的降低,但现在的机器要么很贵,要么误差要手动调整,增加了设计难度(本身这个设计就很复杂了,再加入精度与任务并发的平衡,工程有多大,新手几乎都得凉,这还整么有动力继续搞下去,前方好黑,笑容逐渐消失,脚步逐渐停止);
那么方法还是有的,使用多媒体定时器(winmm.dll),可实现精度 1ms ,看过大部分测试实例,时间间歇在 5ms最为稳定,具体使用方式还需自行百度等查询,毕竟这些资料很多,C#中用的:[DllImport(“winmm.dll”)] 方式。
在 5ms这么高的频率和精度,整么执行更多的任务,这就是设计的重点,另外还会介绍一种非高精度的常规定时器,适用什么时候有任务就什么时候执行,而非高精度定时器那样,不管有没有任务,我就要以这么高的频率同步转发数据。
一、高精度定时器
首先看高精度定时器执行队列设计模型,一个定时器能执行多个子任务,可同时存在多个定时器,这样实现更多的并发处理的数量,许多场景需要的同步频率需要注意,有些频率可能在 25帧,客户端对应的也是 1秒发送25帧 数据,同时接收25帧 返回的数据;这样就达到了一个压力与效率平衡的效果,有些框架设计会支持更多的频率来接收和发送,这只是消息框架的一种(可以再进行查阅质料),继续以 5ms 频率,可以把定时器执行看作一条由箭头的线条,而每隔 5ms 就执行一个子任务当作线条上平均分布的点,可看下图:
![任务执行顺序](https://img-blog.csdnimg.cn/20190926163114198.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjkwODAxMA==,size_16,color_FFFFFF,t_70#pic_center=918x341)
这样看,很明白就看出执行顺序,那么任务的实际频率是 25 帧 ,这如何实现呢?,继续向下看,既然任务是 25帧,1000ms中 25帧的间隔就是 40ms ,再看一个例子,如果任务是 20帧,那么间隔就是 50ms ,看到这些帧数间隔都是 5 的倍数,我们为其中一个帧数制定一个分组,也就是一个高精度定时器,配置一个轮询的值,这个值指示当前组内的第几个,如果以 25帧为例,那么间隔就是 40ms,在这 40ms间隔中,高精度定时器以每 5ms的速率执行了 8 个子任务,按照这个任务数字,将 8个任务交给一个高精度定时器处理,通过配置的轮询值记作下标,8 个任务在同一个数组(列表)中,通过每次调用 +1 ,并在下标值达到子任务数时,让下标重置为 0的方式,执行下标对应的子任务,这样,高精度定时器执行的代码就明确了,只需要每 5ms频率对下标值 +1 并执行下标对应的任务,高精度定时器的模型设计就完成了。如下图:
![分组执行任务](https://img-blog.csdnimg.cn/20190926165919349.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjkwODAxMA==,size_16,color_FFFFFF,t_70#pic_center=969x427)
上面的模型适用精度高,同步效率高的应用,此模型纯属个人研究使用,如有疏漏还请原谅。
二、自动间隔定时器
下面继续另一种定时器设计,适用有任务才执行,没任务不执行,且不会空转消耗多余的性能,当我们有这样的需求功能:有个系统需要在 2s 执行发送消息任务,这样简单设置设置定时就可以了;等等,问题还没完,这只是一种 ,如果一个系统又有,更高频率的任务如:1s 或是频率更低的 5s 甚至 10s 的;还没完,后面又扩了一个模块的功能需要 3s 的任务。。。,我天,拿来这么多无厘头,这时候,系统中如果没有好好规划定时器的使用,越来越多的定时器同时运行,必定会又一个问题,在某时某刻多个定时器同时执行回调任务,包括空转调用,系统会经常的卡顿,这时基于可延时框架设计的定时器,偏差时间会越来越大。
这种多时段,多频率混合且精度在 1s内的任务需要执行,我想到用 AutoResetEvent + System.Threading.Timer 组合实现上面的要求,并去掉不必要的空转。
可变任务队列自动间隔任务执行模型,自动计算下一次执行的时间,在指定时间执行指定任务,多个任务自动合并(这个看具体实现了,模型只提供大概逻辑),具体设计:在定时器创建时,检查到任务队列为空,主循环使用AutoResetEvent进入任务等待,而定时器的执行逻辑只有一个作用,那就是发送AutoResetEvent信号,此外别无他用,当第一个定时任务插入队列时,任务队列为空,便设置定时器为任务要需要执行的时间,且任务可设置其他参数控制当前任务是否循环执行,或者执行次数(这需要一个存储任务与任务参数的对象),定时器时间到达时发送AutoResetEvent信号,主循环AutoResetEvent等待信号接收到时,执行任务队列首位的任务,执行完任务后,设置任务队列下一个任务为任务队列的首位,并更具新的首位的定时参数,重置定时器定时时间,当新的任务插入到队列时,更具执行时间排序,若新插入的任务定时时间,小于定时器定时的时间(定时器定时时间-已过去的时间<插入任务的时间)时,就将定时器重置为新插入任务的定时时间,并设置任务队列首位为当前新插如任务,如此循环往复。
![自动任务执行](https://img-blog.csdnimg.cn/20190926180327860.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjkwODAxMA==,size_16,color_FFFFFF,t_70#pic_center=900x428)
定时器轮询模型的两种设计已经讲解完毕,资料方面确实没有准备,只能动手自己查阅了。
如有误导请联系,我会进行修正。
邮箱 hbck_gwx@qq.com