C#中Timer实现Tick使用精度的问题
目录
Timer实现Tick使用精度
我们想在C#中实现一秒钟执行n次的一个事件,然后其他方法可以监听这个事件,最终实现每一帧随着Tick改变,我们的倒计时开始计数.
在使用Timer过程中发现Timer的精度有问题,最高频率是1秒调用62次,不满足我们的使用需求,100帧每秒,于是我们采用了别的方式实现这样的功能
实现效果
实现误区
我们最早实现方法是直接开启一个新线程,在线程内部开启一个Timer,设定Timer的延迟,但是最终发现它的执行精度最高只能达到62帧每秒,我就算把Timer的间隔时间设置为1ms也是只能执行62帧每秒,原因我们初步推测是因为Timer的精度不足.
解决思路
于是我们前往了C#源码查看,发现源码是通过Stopwatch实现的Timer类,Stopwatch类主要是一个倒计时秒表,既然知道是什么东西了那么就好实现了,我们开启一个新线程,保证线程一直执行就加上无限循环while(true). 在外部 我们开启Stopwatch,然后我们在while中判断秒表是否达到我们的需求,如果达到了那么就调用一个事件,然后在外部监听这个事件,就可以实现了
代码片段
class Program
{
///
/// 10ms trigger ont time
///
private const int tickTime = 10;
private static Action
static void Main(string[] args)
{
Tick += (x) => { Console.WriteLine("Time:" + x); };
Thread t = new Thread(() =>
{
Stopwatch s = new Stopwatch();
s.Start();
long temp = 0;
while (true)
{
if (s.ElapsedMilliseconds >= temp + 10)
{
temp = s.ElapsedMilliseconds;
Tick?.Invoke(temp);
}
}
});
t.IsBackground = true;
t.Start();
while (true) { }
}
}
效率
测试上述代码后发现,设定为10ms执行一次的,按照理论上执行次数是1秒钟100帧,但实际效果是90帧,于是我们得出结论,使用这种方式在10ms的时候,效率是90%,然后我们测试了1ms执行一次的效果,效率为50%,也就是1秒钟执行了500次.
三种Timer组件的区别
timer计时器,每隔间隔的时间就会触发事件。
1. System.Windows.Forms.Timer
--应用于Windows应用程序,基于UI,独占一个线程。
--属性 interval:时间间隔 ms
--事件 Tick事件,如果在此事件中执行的任务过多,会发生阻塞。
--应用 主要应用修改UI元素(窗体的窗体属性)
--注意事项 如果单次执行时间超过设置的间隔时间,会影响下次触发,精度较差。
2. System.Timers.Timer 基于服务
--轻量级的计时器,每隔间隔时间,触发Elapsed事件,可加载成控件使用,也可以利用代码使用(System.Timers.Timer timer2 = new System.Timers.Timer()).
--应用:服务器,获取数据。
--局限:不可以修改UI元素,但可以通过UI元素this.invoke(action)调用委托修改UI元素。
--属性:timer2.interval =1000;timer2.AutoReset = false;//只会印发一次就停止了。
--事件: timer2.Elapsed += Timer_Elapsed;
--启动:timer2.start();
--停止:timer2.stop();
--优点:如果事件里单次执行了耗时的操作,不会使UI失去响应,不会影响下一次触发。
3. System.Threading.Timer 基于线程
--轻量级的计时器,每隔间隔时间,回调方法执行操作,可加载成控件使用,也可以利用代码使用。
--回调方法原型:public Timer(TimerCallback callback,object state,int dueTime,int period);
参数1(state):要使用信息的对象或者设为null;
参数2(dueTime):延迟启动的时间,单位ms;
参数3(period): 时间间隔,ms,period 时间间隔 设置为0或者-1,只会执行一次;Change方法可以让计时器重新启动。
--demo
System.Threading.Timer timer3 = new System.Threading.Timer(new System.Threading.TimerCallback(o=>{
count2+=2;
Action
this.Invoke(act,count2);
}),null,0,1000);
private void ShowCount(int count)
{
txtCount.Text = count.ToString();
}
--对线程池线程执行方法的机制,也就是基于多线程的,精度比较高。
--优点:如果事件里单次执行了耗时的操作,不会使UI失去响应,不会影响下一次触发。
--方法:timer3.Chang(2000,2000);//改变延迟启动时间和时间间隔。
--停止:timer3.Dispose();
--局限:不可以修改UI元素,但可以通过UI元素this.invoke(action)调用委托修改UI元素。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
- .NET Core系列之MemoryCache 初识
- 007手机一键Root(安机网一键Root) v3.0 官方最新版 一键ROOT您的Android手机
- 12306密码被盗了怎么办?12306密码外泄解决方法
- 12个字的qq网名
- 150M迷你型无线路由器怎么设置?
- 192.168.1.1打不开怎么办?路由器192.168.1.1打不开的原因以及解决办法
- 2011年电子报合订本 电子报 编辑部 中文 PDF版 [84M]
- 2015年1月15日小米新旗舰发布会现场图文直播
- 2016.3.1vivo Xplay5新品发布会现场视频直播 优酷直播
- 2016华为P9发布会视频直播地址 4月15日华为P9国行发布会直播