.Net Framework下Timer类之对比

来源:互联网 发布:不列颠空战知乎 编辑:程序博客网 时间:2024/06/01 07:27

原文: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: UIThreadSleeping for 5000 ms...--> Timer Event 4 @ 4:09:36 PM on Thread: UIThreadSystem.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: WorkerThreadSleeping 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: WorkerThreadSystem.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: WorkerThreadSleeping 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: WorkerThreadSystem.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.ThreadingTimer event 所在线程UI threadUI or worker threadWorker thread对象是否thread safe?NoYesNo是否需要Windows Forms?YesNoNoTimer event 是否支持状态变量?NoNoYes初始timer event是否可被延迟?NoNoYesClass 是否支持继承?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

原创粉丝点击