C# 三种定时器的用法

news2024/11/16 7:28:07

目录

1.System.Timers.Timer

2.System.Windows.Forms.Timer

3.System.Threading.Timer

4.简单的封装


这里介绍三种常用的定时器,方便查阅资料或直接复制使用。

1.System.Timers.Timer

System.Timers.Timer 类定义了一个计时器,该计时器按固定间隔触发事件。它主要用于多线程环境,特别是在基于服务器的组件或服务组件中。此类没有用户界面,在运行时不可见,特别适用于后台任务处理。

主要属性和方法

  • Interval:以毫秒为单位,设置或获取引发 Elapsed 事件的时间间隔。
  • AutoReset:设置或获取一个值,该值指示计时器在 Elapsed 事件触发后是否自动重置,并继续计时(true)或停止计时(false)。
  • Enabled:设置或获取一个值,该值指示计时器是否已启用(true)或已禁用(false)。
  • Start():通过将 Enabled 设置为 true 来启动计时器。
  • Stop():通过将 Enabled 设置为 false 来停止计时器。
  • Elapsed 事件:当指定的时间间隔过去时,将触发此事件。该事件处理函数在新的线程中执行,因此不能直接访问UI控件(需通过委托和Invoke方法)。

使用场景

适用于需要按固定时间间隔执行任务的后台服务或应用程序,如定期检查数据库、更新状态信息等。

用法:

namespace Test2
{
    internal class Program
    {
        private static System.Timers.Timer Timer;
        static void Main(string[] args)
        {
            Timer = new System.Timers.Timer();
            Timer.Interval = 2000; //间隔时间2000毫秒
            Timer.AutoReset = true;//是否重复执行
            Timer.Elapsed += Timer_Elapsed;
            Timer.Enabled = true; //或者使用 Timer.Start() 效果一样

            Console.ReadKey();
        }

        private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Console.WriteLine("需要重复执行的代码");
        }
    }
}

2.System.Windows.Forms.Timer

System.Windows.Forms.Timer 控件是Windows窗体环境中的定期事件引发组件。它主要用于单线程环境,特别是在UI更新中。该计时器是同步的,意味着它在UI线程上执行,不会阻塞或干扰UI操作。

主要属性和方法

  • Interval:以毫秒为单位,设置或获取计时器事件之间的时间间隔。
  • Enabled:设置或获取一个值,该值指示计时器是否已启用(true)或已禁用(false)。
  • Start():启动计时器。
  • Stop():停止计时器。
  • Tick 事件:当指定的时间间隔过去时,将触发此事件。与 System.Timers.Timer 不同,Tick 事件在UI线程上执行,因此可以直接访问UI控件。

使用场景

适用于需要按固定时间间隔更新UI元素的场景,如时钟、动画、进度条更新等。

System.Windows.Forms.Timer 可以在 Winform 工具箱中直接拖入到 Winform 界面中,也可以直接在代码中添加,System.Windows.Forms.Timer 在定时器回调中可以调用 Winform 的界面控件,而 System.Timers.Timer 回调内使用 Winform 控件会存在跨线程的错误。

用法同 System.Timers.Timer 差不多,用工具箱中的 Timer 可以少写很多代码。

代码:

using System;
using System.Windows.Forms;

namespace Test1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        System.Windows.Forms.Timer Timer;

        private void Form1_Load(object sender, EventArgs e)
        {
            Timer = new System.Windows.Forms.Timer();
            Timer.Interval = 1000;
            Timer.Tick += Timer_Tick;
            Timer.Start();
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            Console.WriteLine("需要重复执行的代码");
        }
    }
}

3.System.Threading.Timer

System.Threading.Timer 类由线程池调用,专门用于在线程池线程上按固定间隔执行单个回调方法。它是为服务器或后台应用程序设计的,可以优化系统资源的使用。

主要属性和方法

  • Callback:定义在指定时间间隔后调用的回调方法。
  • State:传递给回调方法的对象,作为回调方法的参数。
  • DueTime:计时器第一次触发之前延迟的时间(以毫秒为单位)。
  • Period:计时器每次触发之间的时间间隔(以毫秒为单位)。设置为 Timeout.Infinite 表示计时器只触发一次。
  • Change(Int64, Int64):在计时器启动后更改其 DueTime 和 Period 设置。
  • Dispose():释放 Timer 对象使用的资源。

使用场景

适用于需要定期执行长时间运行或资源密集型任务的后台应用程序,如文件清理、数据同步等。由于回调方法在线程池线程上执行,因此不会影响UI线程的性能。

代码:

namespace Test2
{
    internal class Program
    {
        private static System.Threading.Timer Timer;
        static void Main(string[] args)
        {
            //参数1 要定时执行的回调
            //参数2 定时回调的参数
            //参数3 延迟多少秒开始执行
            //参数4 定时器的间隔时间
            Timer = new System.Threading.Timer(OnTimedEvent, null, 0, 1000);

            Console.ReadKey();
        }

        private static void OnTimedEvent(Object state)
        {
            Console.WriteLine("需要重复执行的代码");
        }
    }
}

可以使用下面的方法来停止定时器

// 暂时停止定时器
Timer.Change(Timeout.Infinite, Timeout.Infinite);

如果需要继续执行定时器,可以使用下面的方法

// 重新启动定时器:初始延迟1000毫秒,每2000毫秒触发一次
Timer.Change(1000, 2000);

其实还有一个定时器 System.Web.UI.Timer,只是现在用的人比较少,这里就不做介绍了。

4.简单的封装

根据上面的代码可以发现,就那几行代码,复制来复制去的有点麻烦,我这里稍微封装一下,一句代码搞定定时器,非常的方便。

新建一个类 TimerScheduler

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

/// <summary>
/// 定时器的封装
/// </summary>
public class TimerScheduler
{
    private static Dictionary<string, ActionSchedulerInfo> SchedulerDic = new Dictionary<string, ActionSchedulerInfo>();

    /// <summary>
    /// 添加定时执行委托
    /// </summary>
    /// <param name="key">唯一的Key</param>
    /// <param name="intervalInSeconds">定时器间隔时间</param>
    /// <param name="isUIThread">是否是UI线程</param>
    /// <param name="action">定时器回调</param>
    public static void Add(string key, double intervalInSeconds, bool isUIThread, Action action)
    {
        if (action == null)
        {
            Console.WriteLine("参数 action 不能为空");
            return;
        }
        if (string.IsNullOrEmpty(key))
        {
            Console.WriteLine("参数 key 不能为空");
            return;
        }
        if (SchedulerDic.ContainsKey(key))
        {
            Console.WriteLine($"{key} 不能重复的添加");
            return;
        }
        if (intervalInSeconds <= 0 || intervalInSeconds > 86400)
        {
            Console.WriteLine($"{key} 的间隔时间超过了指定的范围");
            return;
        }

        var actionScheduler = new ActionSchedulerInfo();
        if (isUIThread)
        {
            actionScheduler.timerUI = new System.Windows.Forms.Timer();
            actionScheduler.timerUI.Interval = (int)TimeSpan.FromSeconds(intervalInSeconds).TotalMilliseconds;
            actionScheduler.timerUI.Tick += (sender, e) => action();
            actionScheduler.timerUI.Start();
        }
        else
        {
            actionScheduler.timer = new System.Timers.Timer();
            actionScheduler.timer.Interval = TimeSpan.FromSeconds(intervalInSeconds).TotalMilliseconds;
            actionScheduler.timer.Elapsed += (sender, e) => Task.Run(action);
            actionScheduler.timer.AutoReset = true;
            actionScheduler.timer.Start();
        }
        SchedulerDic[key] = actionScheduler;
    }

    /// <summary>
    /// 移除定时执行委托
    /// </summary>
    /// <param name="key"></param>
    public static void Remove(string key)
    {
        if (SchedulerDic.TryGetValue(key, out var scheduler))
        {
            if (scheduler.timer != null)
            {
                scheduler.timer.Stop();
                scheduler.timer.Dispose();
            }
            if (scheduler.timerUI != null)
            {
                scheduler.timerUI.Stop();
                scheduler.timerUI.Dispose();
            }
            scheduler.actions = null;
            SchedulerDic.Remove(key);
        }
    }

    /// <summary>
    /// 移除所有的定时器
    /// </summary>
    public static void Dispose()
    {
        foreach (var scheduler in SchedulerDic.Values)
        {
            if (scheduler.timer != null)
            {
                scheduler.timer.Stop();
                scheduler.timer.Dispose();
                scheduler.actions = null;
            }
            if (scheduler.timerUI != null)
            {
                scheduler.timerUI.Stop();
                scheduler.timerUI.Dispose();
                scheduler.actions = null;
            }
        }
        SchedulerDic.Clear();
    }

    public class ActionSchedulerInfo
    {
        public System.Timers.Timer timer { get; set; }
        public System.Windows.Forms.Timer timerUI { get; set; }
        public Action actions { get; set; }
    }
}

添加:

TimerScheduler.Add("Test", 2, false, () =>
{
    Console.WriteLine("这是一个定时器");
});

这里使用了一个 Lambda 表达式,你可以直接替换成一个无参数的方法。

移除:

TimerScheduler.Remove("Test");

移除对应的 key,就能停止和清除这个定时器了。

end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2076446.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大二必做项目贪吃蛇超详解之上篇win32库介绍

文章目录 1. 游戏背景2. 游戏效果演示3. 项目目标4. 前置知识5. Win32 API5. 1 控制台程序(Console)5. 2 控制台屏幕上的坐标 COORD5. 3 GetStdHandle5. 4 GetConsoleCursorlnfo5. 4. 1 CONSOLE_CURSOR_INFO5. 4. 2 SetConsoleCursorlnfo 5. 5 SetconsoleCursorPosition5. 6 Ge…

“汤姆猫除了不会捉杰瑞啥都会”之作为Web服务器,tomcat的常用部署方式 (Tomcat+memcached实现高可用)

目录 企业级WEB应用服务器TOMCAT一、tomcat的功能介绍1.1 安装 Tomcat1.2 tomcat的文件结构和组成1.3 生成tomcat的启动文件 二、结合反向代理实现tomcat部署2.1 常见部署方式介绍2.2 利用 nginx 反向代理实现2.3 实现tomcat中的负载均衡2.3.1 HTTP的无状态&#xff0c;有连接和…

Linux驱动学习之中断与等待队列

本篇分为设备树部分和API接口部分 设备树 想要使用中断&#xff0c;设备树中需要有两个属性&#xff1a; interrupts // 表示要使用哪一个中断, 中断的触发类型等等。 interrupt-parent // 这个中断要接到哪一个设备去? 即父中断控制器是谁 父中…

一种更快成像的新技术

斯旺西大学&#xff08;Swansea University&#xff09;的研究人员为中性原子束显微镜创造了一种新的成像方法&#xff0c;可大大加快显微镜图像的获取速度。中性原子束显微镜已成为科学研究的一个重点&#xff0c;因为它能够对商用显微镜无法成像的表面进行成像&#xff0c;例…

mysql集群从零开始搭建

文章目录 MySQL集群linux下部署mysqlmysql主从复制master配置配置slave新的slave加入延迟复制慢查询多线程原理 半同步模式原理gat模式启动半同步模式 mysql高可用之组复制&#xff08;MGR&#xff09;实现mysql组复制 mysql路由具体实现 mysql高可用之MHAMHA部署实施安装MHA软…

Codeforces Round 968 (Div. 2 ABCD1D2题) 视频讲解

A. Turtle and Good Strings Problem Statement Turtle thinks a string s s s is a good string if there exists a sequence of strings t 1 , t 2 , … , t k t_1, t_2, \ldots, t_k t1​,t2​,…,tk​ ( k k k is an arbitrary integer) such that: k ≥ 2 k \ge 2 k≥…

接口自动化测试利器,使用Rest Assured进行REST API测试

我们在做接口测试时&#xff0c;一般在代码中会使用HttpClient&#xff0c;但是HttpClient相对来讲还是比较麻烦的&#xff0c;代码量也相对较多&#xff0c;对于新手而言上手会比较难一点&#xff0c;今天我们来看下另一个接口测试工具包REST Assured REST Assured是一个流行…

Blazor官方文档学习记录

Blazor官方文档学习记录 1 官方文档2 Blazor教程-生成首个应用3 项目结构4 基础知识4.1 生态4.2 Razor组件指令顺序4.3 Razor组件的初始化方法 5 注意 1 官方文档 https://dotnet.microsoft.com/zh-cn/apps/aspnet/web-apps/blazor2 Blazor教程-生成首个应用 https://dotnet.…

Python | Linux | 解析Himawari-8/9 | Standard Data

写作前面 之前一个相关的工作需要解析Himawari-8/9 Standard Data文件&#xff0c;因为他是二进制的&#xff0c;之前没有处理过&#xff0c;导致完全摸不着头脑。在网上找了中英文搜索找了好久&#xff0c;虽然也找到了公开的解析代码&#xff0c;但是放在自己的数据这感觉总是…

趣味算法------猴子吃桃(循环,递归双重解法)

题目描述 猴子第一天摘下若干个桃子&#xff0c;当天吃了一半&#xff0c;后面又多吃一个。第二天早上又将剩下的桃子吃掉一半&#xff0c;又多吃了一个。后面每天猴子都吃了前一天剩下的一半零一个。到第十天想再吃时&#xff0c;只剩下一个桃子。求第一天共摘了多少桃子。 …

鸿蒙(API 12 Beta3版)【获取音视频元数据】音频播放与录制

使用AVMetadataExtractor可以实现从原始媒体资源中获取元数据&#xff0c;本开发指导将以获取一个音频资源的元数据作为示例&#xff0c;向开发者讲解AVMetadataExtractor元数据相关功能。视频资源的元数据获取流程与音频类似&#xff0c;由于视频没有专辑封面&#xff0c;所以…

【中仕公考怎么样】公务员备考小建议

2025年国考在即&#xff0c;掌握正确的备考方法很重要&#xff01;中仕为大家简单分享4点小技巧。 1. 在提升行测分数时&#xff0c;可以采用大量的练习题、整理题以及关注往年核心考点的方式。无论处于准备过程的哪一阶段&#xff0c;对各类题型进行深入分析并掌握相应的解题…

C++ | Leetcode C++题解之第373题查找和最小的K对数字

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {int m nums1.size();int n nums2.size();auto count [&](int target){long long …

怎么用AI生成PPT演讲稿?5个方法教你快速生成

想象一下&#xff0c;你正在准备一场关于“墨西哥是如何走到今天这一步的”演讲&#xff0c;而你却苦于如何将复杂的历史背景、经济变迁以及文化特色等内容有机地整合进一份PPT中。 这时候&#xff0c;一款好的AI自动生成PPT的工具就能派上用场了。它不仅能够帮助你快速构建起…

C# 使用 WinForm MDI 模式管理多个子窗体程序的详细步骤

前言 嗨&#xff0c;各位码农们&#xff01;今天我们要来聊聊如何在 C# 的 WinForms 应用程序中用 MDI&#xff08;Multiple Document Interface&#xff09;模式来优雅地管理多个子窗体。 如果你曾经对着一堆乱七八糟的窗体不知所措&#xff0c;或者想要让你的应用程序看起来…

基于SpringBoot的线上教学平台系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言 Java 数据库 MySQL 技术 SpringBoot框架&#xff0c;Java语言 工具 IDEA/Eclipse、Navicat、Maven 系统展示 首页 管理员功能模块 学员功能模块 前台首页…

16行为型设计模式——策略模式

一、策略模式简介 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一系列的算法&#xff0c;将每一个算法封装起来&#xff0c;并使它们可以相互替换。具体的算法选择交由客户端决定&#xff0c;即不同的算法可以在运行时动态地&a…

后端微服务架构:构建分布式博客系统

后端微服务架构&#xff1a;构建分布式博客系统 在当今的软件开发领域&#xff0c;微服务架构已经成为构建可扩展、灵活且易于维护的应用程序的主流选择。本文将探讨如何利用微服务架构来设计和实现一个分布式的博客系统。 1. 微服务架构简介 微服务架构是一种将应用程序分解…

练习题 期望dp

题目 分析&#xff1a; 首先注意到期望有线性性&#xff1a; E ( a b ) E ( a ) E ( b ) E(ab)E(a)E(b) E(ab)E(a)E(b)&#xff0c;其中 a a a、 b b b不要求相互独立。 因为网上很多地方的证明不严谨&#xff0c;所以这里证明一下&#xff1a; E ( a b ) ∑ i i ⋅ P …

C语言基础(十八)

1、共用体&#xff08;Union&#xff09;是一种特殊的数据类型&#xff0c;也被称为联合体&#xff0c;它允许在相同的内存位置存储不同的数据类型&#xff0c;每次只能存储其中一种类型的值。共用体是一种数据结构&#xff0c;多个不同类型的变量能够共享同一段内存空间。在C语…