定时器是CS模式下经常会用到的组件,一般作为初学者(Me Too)都会直接从工具箱中拖一个TImer控件,然后在Timer_Tick中写自己的处理操作,我一开始也是这样使用定时器,后来才发现自己忽略了好多东西:首先,定时器分三种,而拖控件生成的TImer只是其中之一,下面简单介绍一下三种定时器的区别:
- System.Windows.Forms.Timer:这种定时器就是直接拖放控件生成的定时器,该定时器是通过Windows消息机制实现的,因此就决定该定时器的“定时”效果跟当前应用程序的运行情况息息相关,当前应用程序UI线程的操作会直接影响该TImer的“定时”效果,比如,在应用程序的UI线程(按钮操作,或者其他前台操作)比较耗费时间,就会影响TImer的定时响应,因此,你可能会碰到,定时器的执行频率和设定的定时间隔相差很大的状况,请看下面实例:
-
private void timer1_Tick(object sender, EventArgs e) { Console.WriteLine("----" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + "----" ); }
这是定时器里面处理的操作,同时如果,界面上UI线程的操作比较耗时(就算不太耗时,依旧会影响定时器,只不过影响的不明显而已),如下所示:在按钮的触发操作中包含一个耗时的操作
-
private void button1_Click(object sender, EventArgs e) { string str = ""; for (int i = 0; i < 9000000; i++) { for (int j = 0; j < 20; j++) { str = i.ToString(); } } }
那么这个时候,启动程序,定时器开始每100毫秒输出当前时间,如果你再点击button1,你就会发现,控制台不再输出信息,等过几秒之后,才又开始输出,如下图:
- 这说明UI线程的操作阻断了定时器的调用。同时,如果TImer_Tick里面的操作比较耗费时间,也会造成界面卡死,同时定时器的“定时”也就失去了意义,如下所示:
-
private void timer1_Tick(object sender, EventArgs e) { Console.WriteLine("----" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + "----"); string str = ""; for (int i = 0; i < 9000000; i++) { for (int j = 0; j < 5; j++) { str = i.ToString(); } } }
这样,在一个定时间隔为100毫秒的定时器里,进行了耗时的操作,最后导致界面卡死,而且,定时器的间隔也被拉长了,如下图所示:
- 综上所述,不建议使用该类型的定时器。
-
- System.Threading.Timer:是用于 Windows 窗体的更佳选择。要获取基于服务器的计时器功能,可以考虑使用 System.Timers.Timer,它可以引发事件并具有其他功能