多种Timer的场景应用

  三种Timer组件
  
  .Net框架提供了三种常规Timer组件,分别是System.Windows.Forms.Timer、System.Timers.Timer和System.Threading.Timer。实际最常用的也就是前两种,而且应用场景比较明确。
  
  System.Windows.Forms.Timer
  
  Forms.Timer基于单线程,也就是基于主线程运行。它的应用场景一般是:
  
  Winform项目,WPF项目
  
  小型任务操作,比如界面更新。而比如数据库交互这种需要等待和响应的操作就不合适了
  
  不适合时间粒度比较细的项目。比如你要发起一个定时器,和硬件设备进行交互。此Timer是在主线程上进行中断,会造成硬件的交互和UI操作争夺资源。
  
  Timer timerWft = new Timer();                   //System.Windows.Forms.Timer
  
  private void Form1_Load(object sender, EventArgs e)
  
  {
  
  //System.Windows.Forms.Timer
  
  timerWft.Tick += TimerWft_Tick;     //绑定触发事件
  
  timerWft.Interval = 50;              //设定执行间隔时间(ms)
  
  }
  
  /*
  
  * System.Windows.Forms.Timer特点
  
  * 1. 运行在主线程内,因此不是多线程运行
  
  * 2. 因为运行在主线程内,所以它的执行机制是中断机制,即在UI消息泵内制造一个中断,来处理Timer的定时处理代码
  
  * 3. 因为是中断机制,所以定时处理代码不能过于耗时,耗时将导致UI不流畅或者卡死
  
  *
  
  * 因此,这种Timer只能用于Winform下,定时处理代码很简单,耗时较小的应用场景
  
  * 何为消息泵:Main方法中的打开主窗体的代码:Application.Run(new Form1())就是启动一个消息处理循环并打开主窗体
  
  */
  
  private void btnWft_Click(object sender, EventArgs e)
  
  {
  
  if (!timerWft.Enabled)
  
  {
  
  lbMsg.Items.Clear();
  
  btnWft.Text = "停止";
  
  timerWft.Start();                   //使用Start()方法或者Enable = true属性来启动Timer
  
  //timerWft.Enabled = true;
  
  }
  
  else
  
  {
  
  btnWft.Text = "启动";
  
  timerWft.Stop();
  
  }
  
  }
  
  private void TimerWft_Tick(object sender, EventArgs e)
  
  {
  
  AddMsg(string.Format("{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")));
  
  }
  
  因为这个Timer是继承自Component的,因此它可以从工具箱上拖放到设计界面上。不过一般不建议这么做,因为手写也非常方便。
  
  System.Timers.Timer
  
  这个Timer基于多线程的:
  
  不限项目类型
  
  其他不适合Windows.Forms.Timer的场景,都建议使用它
  
  NsTim.Timer timerTim = new NsTim.Timer();      //System.Timers.Timer
  
  private void Form1_Load(object sender, EventArgs e)
  
  {
  
  //System.Timers.Timer
  
  timerTim.Elapsed += TimerTim_Elapsed;   //绑定触发事件
  
  timerTim.Interval = 50;                  //设定执行间隔时间(ms)
  
  }
  
  /* System.Timers.Timer 的特点
  
  * 1. Timer代码在独立线程内运行,原则上不会卡UI界面
  
  * 2. 因为是多线程执行,所以定时执行的方法是由子线程触发的,而它要操控UI线程的对象,此时需要跨线程
  
  */
  
  private void btnTim_Click(object sender, EventArgs e)
  
  {
  
  if (!timerTim.Enabled)
  
  {
  
  lbMsg.Items.Clear();
  
  btnTim.Text = "停止";
  
  timerTim.Start();                   //使用Start()方法或者Enable = true属性来启动Timer
  
  //timerWft.Enabled = true;
  
  }
  
  else
  
  {
  
  btnTim.Text = "启动";
  
  timerTim.Stop();
  
  }
  
  }
  
  private void TimerTim_Elapsed(object sender, NsTim.ElapsedEventArgs e)
  
  {
  
  if (this.IsHandleCreated)  //判断IsHandleCreated,以避免窗体关闭时窗体句柄销毁导致 this 失效,而导致后续执行异常
  
  {
  
  //必须使用BeginInvoke异步调用UI对象
  
  this.BeginInvoke(new Action(() =>
  
  {
  
  AddMsg(string.Format(www.dasheng178.com "{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")));
  
  }));
  
  }
  
  }
  
  我们可以看到,在Timer的线程中和UI交互,必须使用BeginInvoke()发起异步跨线程操作,或者使用Invoke()发起同步跨线程操作。为了不卡界面,一般都会使用BeginInvoke异步调用。
  
  System.Threading.Timer
  
  这个Timer也是基于多线程的,但我们仔细分析它的命名空间,我们发现它是有侧重的。上面第二种是System.Timers,侧重于Timers,可以说它是“专业的Timer组件”,而这个Timer的命名空间是System.Threading,是基于线程的Timer,可以理解为,它是为线程中的场景服务的。它的特点:
  
  不限项目类型
  
  适合基于多线程中的Timer场景,比如想在多线程执行中发起一个Timer
  
  所以我们会发现,如果想按常规的方式使用这个Timer,是很别扭的。常规的Timer,都可以自由控制Start(), Stop(), 但它没有。所以它适合的是“多线程中的Timer场景”,可以说是非常精确的一个描述。理由如下:
  
  命名空间的定义Threading,说明了设计者想要它用于多线程场景
  
  它没有定义显式的停止Timer的方法,因为在线程运行场景下没有必要。一个线程的正确用法,往往是应该迅速执行、迅速结束的,因此没有必要给它提供Stop方法。所以我们发现,停止这个Timer的方式,是 timer = null,将Timer扔给垃圾收集器。
  
  从它的方法参数中,可以看到它的回调方法和其他的Timer不同,其他的Timer都是event,而它是Callbacks,适合用匿名委托,把代码写在线程方法内,这样线程代码和回调代码不分离,可读性更好。
  
  NsThr.Timer timerThr;                          //System.Threading.Timer
  
  /* System.Threading.Timer的特点
  
  * 1. Timer代码在独立线程内运行,原则上不会卡UI界面
  
  * 2. 因为是多线程执行,所以定时执行的方法是由子线程触发的,而它要操控UI线程的对象,此时需要跨线程
  
  * 3. 可以看出它的停止代码写的非常丑陋,主要是它并没有提供停止Timer的方法。它的使用场景是在多线程中发起Timer,一个线程的执行原则上很快结束,所以没有必要
  
  * 4. 我们会发现这个Timer继承自MarshalByRefObject,这是个具有跨应用程序域特性的对象,比如应用程序域A的代码要操控应用程序域B的Timer,那只能用它了。
  
  */
  
  private void btnThr_Click(object sender, EventArgs e)
  
  {
  
  if (timerThr == null)
  
  {
  
  lbMsg.Items.Clear();
  
  btnThr.Text = "停止";
  
  timerThr = new NsThr.Timer(new NsThr.TimerCallback((o)=>
  
  {
  
  if (this.IsHandleCreated)
  
  {
  
  this.BeginInvoke(new Action((www.michenggw.com  ) =>
  
  {
  
  AddMsg(string.Format("{0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")));
  
  }));
  
  }
  
  }), null, 50, 50);
  
  }
  
  else
  
  {
  
  btnThr.Text = "启动";
  
  timerThr.Change(0, NsThr.www.mcyllpt.com Timeout.Infinite);
  
  timerThr = null;
  
  }
  
  }
  
  总结
  
  System.Windows.Forms.Timers 适合基于Winform,WPF的项目,同时执行任务比较简单快速的场景,比如UI显示。
  
  System.Timers.Timer 适合各种项目,用于执行任务耗时较长,以及对交互有更高要求的场景。
  
  System.Threading.Timer 适合用于在多线程中发起Timer的场景。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值