C# 中定时器的种类和常用方法

▪ 前言

在 .Net 常用的定时器类有下面三种,使用定时器时需要设定参数,如间断时间、定时器计溢出后的回调函数、延时、开始等,定时器的主要方法有开始、终止等,不同的定时器实现上述的方法会有一些差异,本文会针对具体的定时器一一举例说明。

  • System.Windows.Forms.Timer 定时器类
  • System.Threading.Timer 定时器类
  • System.Timers.Timer 定时器类

▪ System.Windows.Forms.Timer

从这个定时器的命名空间可以看出,.Net 设计这个定时器的目的是为了方便程序员在 Window Form 中使用的定时器。

当一个 System.Windows.Forms.Timer 类被构造时,当前定时器会和当前线程进行关联。而当计时器的计满后,一个定时器消息将被插入到当前线程的消息队列中。当前线程逐一处理消息中的所有消息,并一一派发给各自的处理方法。

这样的机制和利用工作者进程定时有很大的区别,System.Windows.Forms.Timer 类型并没有涉及多线程的操作,定时器的设置、定时方法的执行都在同一个线程之上。这就意味着 System.Windows.Forms.Timer 并不能准确计时,尤其当消息阻塞时,定时器的误差将会更大,因为定时器消息只能等待在前面的所有消息处理完后才能得到处理。但是因为 System.Windows.Forms.Timer 类型的定时器并不涉及多线程的操作,因此是线程安全的,不会发生回调方法重入的问题。

主要使用步骤如下:

- System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer(); // 实例化 
- myTimer.Tick += new EventHandler(`CallbackFunc`); // 给 Timer 挂起事件
- myTimer.Enabled = true; // 使 Timer 可用
- myTimer.Interval = 1000; // 设置时间间隔,以毫秒为单位
- myTimer.Stop(); // 如果要暂停计时则使用Stop()方法
- myTimer.Enabled = false; // 若要停止使用 Timer,则使之不可用

System.Windows.Forms.Timer 例程:

namespace AppDemo  
{  
    public partial class MainForm : Form  
    {  
        // 实例化一个 Timer
        // 需要设置为全局变量,否则定时器可能就执行一次
        System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer(); 
        
        // 构造函数
        public MainForm(){  
            InitializeComponent();  
        }  

        // 开始计时
        private void uiTimeStartBtn_Click(object sender, EventArgs e)
        {   
            myTimer.Tick    += new EventHandler(this.uiTimeStartBtn_ClickTimer);  // 给Timer 挂起事件  
            myTimer.Enabled  = true;  // 使 Timer 可用  
            myTimer.Interval = 1000;  // 设置时间间隔,以毫秒为单位  
        }
        
        // 停止计时
        private void uiTimeStopBtn_Click(object sender, EventArgs e)  
        {  
            myTimer.Stop();
        } 
        
        // 回调函数  
        private void uiTimeStartBtn_ClickTimer(object sender, EventArgs e){   
            // 获取系统时间 20:16:16
            uiTextBox.Text = DateTime.Now.ToLongTimeString().ToString();  
        }  
    }  
}

▪ System.Threading.Timer

这个定时器类的使用相对复杂,但同时它也是最优化的一个定时器类型

System.Threading.Timer 的定时方法在独立的线程上执行,定时时间更为准确。所有的对象有一个线程控制,当下一个定时到达时,该线程会负责在线程中获得一个新的工作者线程,用以执行相应的回调方法。

虽然这个定时器是相对最优化的一个定时器类型,但是从其机制上来讲,其并不是线程安全的,可能会出现回调方法重入的问题。

解释下方法重入,是一个有关多线程编程的概念,意思大概是:同一程序中,多个线程同时运行时,就可能发生同一个方法被多个进程同时调用的情况。当这个方法中存在一些非线程安全的代码时,方法重入会导致数据发生同步错误的bug。

主要使用步骤如下:

- System.Threading.Timer myTimer = new System.Threading.Timer(new  System.Threading.TimerCallback(`CallbackFunc`), null, 0, 1000);
// 编写 `CallbackFunc` 回调函数,格式:private void TimerCall(object xxx){ ... }
// 使用 `Change(Int32, Int32)` 方法来修改定时器参数实现停止、重新开始等
// 使用 `Dispose()` 方法释放定时器资源

System.Threading.Timer例程:

namespace AppDemo  
{  
    public partial class MainForm : Form  
    {  
        // 实例化一个 Timer
        // 需要设置为全局变量,否则定时器可能就执行一次
        Timer myTimer = new Timer(); 
        
        // 构造函数
        public MainForm(){  
            InitializeComponent();  
        }  

        // 开始计时
        private void uiTimeStartBtn_Click(object sender, EventArgs e)
        {   
            // 1S定时器
            // 必须将 new Timer 赋值给一个全局变量,
            // 否则 uiTimeStartBtn_Click() 函数执行结束后定时器将失效
            myTimer = new Timer(new TimerCallback(Say), null, 0, 1000);  
        }
        
        // 停止计时
        private void uiTimeStopBtn_Click(object sender, EventArgs e)  
        {  
            myTimer.Stop();
        } 
        
        // 回调函数  
        private void uiTimeStartBtn_ClickTimer(object sender, EventArgs e){   
            // 获取系统时间 20:16:16
            uiTextBox.Text = DateTime.Now.ToLongTimeString().ToString();  
        }  
    }  
}

C# 中可以直接使用 Timer ,系统会自动调用 System.Threading.Timer

▪ System.Timers.Timer

这是一个相对较旧的类型,它和 System.Threading.Timer 一样,可以由工作者线程来执行回调方法,但同时它也可以在 IDE 环境中被拖到窗体控件上,这个时候它的行为非常类似于 System.Windows.Forms.Timer类型,在消息过多时其定时并不准确。

System.Timers.Timer 可以视为 System.Threading.Timer 的一个包装,其类型设计相对古老,不建议使用该定时器。

System.Timers.Timer 例程:

System.Timers.Timer myTimer = newSystem.Timers.Timer(5000);  // 设置时间间隔为5秒

private void Form1_Load(object sender,EventArgs e)  
{  
    myTimer.Elapsed += newSystem.Timers.ElapsedEventHandler(Timer_TimesUp);  
    myTimer.AutoReset = false;  // 每到指定时间Elapsed事件是触发一次(false),还是一直触发(true)  
}  
  
private void btnStart_Click(objectsender, EventArgs e)  
{  
    myTimer.Enabled = true;  // 是否触发Elapsed事件  
    myTimer.Start();  
}

private void Timer_TimesUp(objectsender, System.Timers.ElapsedEventArgs e)  
{  
    // 到达指定时间5秒触发该事件输出 HelloWorld!!!!  
    System.Diagnostics.Debug.WriteLine("HelloWorld!!!!");  
}

private void btnStop_Click(objectsender, EventArgs e)  
{  
    myTimer.Stop();  
    System.Diagnostics.Debug.WriteLine("未到指定时间5秒提前终结!!!");  
}  

▪ System.Windows.Threading.DispatcherTimer 类型(补充)

System.Windows.Threading.DispatcherTimer 集成到按指定时间间隔和指定优先级处理的 Dispatcher 队列中的计时器。因为 DispatcherTimer 操作与其他操作一样被放置到 Dispatcher 队列中,何时执行 DispatcherTimer 操作取决于队列中的其他作业及其优先级,因此它不能保证会正好在时间间隔发生时执行计时器,但能够保证不会在时间间隔发生之前执行计时器。

如果 System.Timers.Timer 用于 WPF 应用程序,则值得注意的是 System.Timers.Timer 运行于不同于 User Interface(UI) 线程的其他线程上。 为了访问 User Interface (UI) 线程上的对象,需要使用 InvokeBeginInvoke 将操作发布到 User Interface (UI) 线程的 Dispatcher 上。

▪ 参考博客链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值