ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

.Net中的计时器Timer你真的会用吗?

2022-09-11 12:31:08  阅读:154  来源: 互联网

标签:定时器 System Timer 线程 timer 计时器 Net ID


一、Timer存在的问题

注意:下面演示的Timer都是指的System.Threading的Timer类。

先看以下代码:

    //实例化定时器,并以1000毫秒/次的频率执行
    Timer timer = new(Test, null, 0, 1000);

    //第1个参数指“在调用指定的回调方法之前延迟的时间量”
    //第2个参数指“回调方法的调用之间的时间间隔”
    timer.Change(0, 0);

    //定时执行的业务
    void Test(object? state)
    {
        //获取当前的线程ID
        int id = Thread.CurrentThread.ManagedThreadId;

        //获取一个随机数
        Random random = new Random();
        int roundId = random.Next(1, 10000);

        Console.WriteLine($"{DateTime.Now} 线程ID = {id}_{roundId} 开始执行");

        //模拟耗时的操作
        Thread.Sleep(3000);

        Console.WriteLine($"{DateTime.Now} 线程ID = {id}_{roundId} 结束执行");
    }

解释一下上面的代码:
创建一个定时器timer对象,以1000毫秒的频率循环执行回调方法Test,在方法Test中模拟一个耗时的操作,每次会耗费3000毫秒。为了区分每次执行,通过线程ID和一个随机数作为唯一ID。
程序执行结果如下:

通过上图可以看出,第一次执行Test回调方法还没结束,就开始执行了第2次定时任务,在很多业务场景中,这是不允许的,这会导致很多不必要的麻烦,这也是在我们使用Timer的时候,需要重点关注的。

二、正确的做法

步骤:
1、在创建定时器Timer时,指定Change()的第2个参数为Timeout.Infinite,这样,定时器就只会出发一次。
2、在回调方法中,再次调用Change(),同样需要指定参数为Timeout.Infinite。

Timer _timer = null;

//实例化定时器,并以1000毫秒/次的频率执行
_timer = new(Test, null, 0, 1000);

//第1个参数指返回前timer,不需要等待
//第2个参数指不“超时时间无穷大”,如果第一个循环任务一直没完成,一直等待下去
_timer.Change(0, Timeout.Infinite);

void Test(object? state)
{
    //获取当前的线程ID
    int id = Thread.CurrentThread.ManagedThreadId;

    //获取一个随机数
    Random random = new Random();
    int roundId = random.Next(1, 10000);

    Console.WriteLine($"线程ID = {id} 开始执行,{roundId}");

    //模拟耗时的操作
    Thread.Sleep(3000);

    Console.WriteLine($"线程ID = {id} 结束执行,{roundId}");

    //这里需要再次启动下一个定时任务
    _timer.Change(0, Timeout.Infinite);
}

执行的结果:

通过上图可以看出,每次定时任务执行完后,才会继续执行下一个定时任务。

三、Timer的释放

Timer对象垃圾回收时,它的终结代码告诉线程池取消计数器,使它不再触发。所以,在使用Timer对象时,要确定有一个变量在保持Timer对象的存活,否则对你的回调方法的调用就会停止。

四、多种类型的定时器区别

1、System.Threading的Timer类

这个就是上文讨论的定时器,也是最好的定时器,它是通过线程池去处理的,多线程的(通过上图可以看出,每次的线程ID都不一样),推荐使用。

2、System.Windows.Forms的Timer类

单线程的定时器,不会存在多线程并发的问题。

3、System.Windows.Threading的DispatcherTimer类

这个类是System.Windows.Forms的Timer类在Silverlight和WPF应用程序中的等价物。

4、Windows.UI.Xaml的DispatcherTimer类

这个类是System.Windows.Forms的Timer类在Windows.Store应用程序中的等价物。

5、System.Timers的Timer类

这个定时器本质上是System.Threading的Timer类的扩展类,Microsoft使它在设计器(Winform等项目)中更容易使用。
但是,这个类是好多年前,Microsoft还没有理清线程处理和计时器的时候添加到FCL中的,所以存在一定的缺陷(我也没遇到过)。
所以,强烈建议不要使用这个Timer,推荐使用System.Threading.Timer类。除非,你真的必须要用它。

标签:定时器,System,Timer,线程,timer,计时器,Net,ID
来源: https://www.cnblogs.com/myblog2021/p/16683796.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有