.Net Framework下Timer类之对比

原文:http://msdn.microsoft.com/en-us/magazine/cc164015.aspx

原作者:Alex Calvo,is a Microsoft Certified Solutions Developer for .NET. When he's not reading, coding, or meditating, he's playing guitar. You can reach Alex at  acalvo@hotmail.com.

注意: 有删节,仅译出其要点而已,也有自己添加的理解。

概要:
   .NET Framework Class Library提供了三种不同的时钟类:System.Windows.Forms.Timer, System.Timers.Timer  and System.Threading.Timer.各有不同的用武之地,本文旨在介绍其用法。


内容:
       System.Windows.Forms.Timer
       System.Timers.Timer
       System.Threading.Timer
       Dealing with Timer Event Reentrance
       Conclusion


1)System.Windows.Forms.Timer

          该类的最大特点是其与Winforms App同步,也就是说它的Tick events与UI在同一个线程执行。如果在响应函数执行耗时较多的话,则会出现UI无响应的情况。由此可见该类比较适用一些比较简单的情况。
     原文链接中给出了一些演示示例,供读者来理解该类:
System.Windows.Forms.Timer Started @ 4:09:28 PM
--> Timer Event 1 @ 4:09:29 PM on Thread: UIThread
--> Timer Event 2 @ 4:09:30 PM on Thread: UIThread
--> Timer Event 3 @ 4:09:31 PM on Thread: UIThread
Sleeping for 5000 ms...
--> Timer Event 4 @ 4:09:36 PM on Thread: UIThread
System.Windows.Forms.Timer Stopped @ 4:09:37 PM
          从上面代码可以看出,在其响应函数中休眠5000ms,这五秒钟的Timer Event就失效了。足见该Timer Event是在UI线程中执行的。此外要注意的是,尽管该类的Interval 最小可以为1ms,但是官方的文档说明该类大概只能精确到55ms.
   下面代码是使用System.Windows.Forms.Timer class 示例:
System.Windows.Forms.Timer tmrWindowsFormsTimer = new 
    System.Windows.Forms.Timer();
tmrWindowsFormsTimer.Interval = 1000;
tmrWindowsFormsTimer.Tick += new 
    EventHandler(tmrWindowsFormsTimer_Tick);
tmrWindowsFormsTimer.Start();
•••
private void tmrWindowsFormsTimer_Tick(object sender, 
    System.EventArgs e) {
  //Do something on the UI thread...
}


2)System.Timers.Timer

          . Net Framework称该类是专为多线程环境而设计,且该类的对象是thread-safe的。不同于System.Windows.Forms.Timer,该类的Timer Event是在worker thread(来自线程池)中执行的,这就带来一个问题,如果你的响应函数中涉及到UI操作的话,那么一定要回调到UI线程执行。不过,System.Timers.Timer class提供了一种简单的方式来克服这种麻烦,它采用了“SynchronizingObject ”属性,若将UI forms 赋值于该属性,则SynchronizingObject.Begin.Invoke可让Timer Event在UI线程执行。考虑到UI的responsiveness,我觉得这个属性有些鸡肋。
    演示代码:

System.Timers.Timer Started @ 5:15:01 PM
--> Timer Event 1 @ 5:15:02 PM on Thread: WorkerThread
--> Timer Event 2 @ 5:15:03 PM on Thread: WorkerThread
--> Timer Event 3 @ 5:15:04 PM on Thread: WorkerThread
Sleeping for 5000 ms...
--> Timer Event 4 @ 5:15:05 PM on Thread: WorkerThread
--> Timer Event 5 @ 5:15:06 PM on Thread: WorkerThread
--> Timer Event 6 @ 5:15:07 PM on Thread: WorkerThread
--> Timer Event 7 @ 5:15:08 PM on Thread: WorkerThread
--> Timer Event 8 @ 5:15:09 PM on Thread: WorkerThread
System.Timers.Timer Stopped @ 5:15:10 PM
    使用示例:
System.Timers.Timer tmrTimersTimer = new System.Timers.Timer();
tmrTimersTimer.Interval = 1000;
tmrTimersTimer.Elapsed += new 
    ElapsedEventHandler(tmrTimersTimer_Elapsed);
tmrTimersTimer.SynchronizingObject = this; //Synchronize with 
                                           //the current form...
tmrTimersTimer.Start();
•••
private void tmrTimersTimer_Elapsed(object sender, 
    System.Timers.ElapsedEventArgs e) {
  // Do something on the UI thread (same thread the form was 
  // created on)...
  // If we didn't set SynchronizingObject we would be on a 
  // worker thread...
}
    这里有个问题需要注意,由于timer event是在独立线程中执行的,那么有可能用户已经调用stop函数了,仍会产生timer event事件。ElapsedEventArgs 中包含了一个“SignalTime ”属性,表示已经过去的时间,用户可以将这个时间与stop函数的调用时间相比,以决定是否继续执行响应函数。笔者在这里就遇到一个类似的问题,在窗体函数已经销毁后,仍在timer event响应函数中调用Invoke函数,导致了异常,通过该属性则可避免类似情况。

3)System.Threading.Timer
    该类可以说是三个类中最灵活的一个,但是其对象本身却并非thread-safe的。此外,其使用方式也与前二者不同:
public Timer(TimerCallback callback, object state, long dueTime, 
             long period);
public Timer(TimerCallback callback, object state, UInt32 dueTime, 
             UInt32 period);
public Timer(TimerCallback callback, object state, int dueTime, 
             int period);
public Timer(TimerCallback callback, object state, TimeSpan dueTime, 
             TimeSpan period);
    演示代码:
System.Threading.Timer Started @ 7:17:11 AM
--> Timer Event 1 @ 7:17:12 AM on Thread: WorkerThread
--> Timer Event 2 @ 7:17:13 AM on Thread: WorkerThread
--> Timer Event 3 @ 7:17:14 AM on Thread: WorkerThread
Sleeping for 5000 ms...
--> Timer Event 4 @ 7:17:15 AM on Thread: WorkerThread
--> Timer Event 5 @ 7:17:16 AM on Thread: WorkerThread
--> Timer Event 6 @ 7:17:17 AM on Thread: WorkerThread
--> Timer Event 7 @ 7:17:18 AM on Thread: WorkerThread
--> Timer Event 8 @ 7:17:19 AM on Thread: WorkerThread
System.Threading.Timer Stopped @ 7:17:20 AM
    与 System.Timers.Timer class相比较, 该类并没有“SynchronizingObject ”这个属性,也就是说,若在响应函数中涉及UI操作,则需用户自己调用Invoke或者BeginInvoke。

4)Timer event重复进入问题
    对于System.Timers.Timer class和System.Threading.Timer,其timer event异步执行的,还有一个问题需要注意。如果响应函数执行时间超过了Interval值,那么响应函数会被重复进入,那么在这里就特别需要注意变量的同步了。如果读者不想反复进入呢,那么可以参考如下示例:

private void tmrTimersTimer_Elapsed(object sender, 
    System.Timers.ElapsedEventArgs e) {
    tmrTimersTimer.Enabled = false;
    System.Threading.Interlocked.Increment(ref tickCounter);
    Thread.Sleep(5000);
    MessageBox.Show(tickCounter.ToString());
    tmrTimersTimer.Enabled = true;
}
           在响应函数中操作其Enabled属性。

5)总结
Timer Classes in the .NET FCL

System.Windows.FormsSystem.TimersSystem.Threading
Timer event 所在线程UI threadUI or worker threadWorker thread
对象是否thread safe?NoYesNo
是否需要Windows Forms?YesNoNo
Timer event 是否支持状态变量?NoNoYes
初始timer event是否可被延迟?NoNoYes
Class 是否支持继承?YesYesNo

相关文章:
Windows Forms: Give Your .NET-Based Application a Fast and Responsive UI with Multiple Threads

背景信息:
Programming the Thread Pool in the .NET Framework: Using Timers
.NET Framework Class Library

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值