C# 定时器和后台任务

一、定时器概述

为什么需要定时器?

在运动控制系统中,定时器用于:

  • 周期性任务:如每100ms读取一次轴位置

  • 延时操作:如等待某个动作完成后再执行下一步

  • 状态监控:如实时检测轴的运动状态

  • 定时触发:如定时保存数据、定时报警检测

三种定时器对比

定时器类型 命名空间 线程 适用场景
System.Windows.Forms.Timer System.Windows.Forms UI线程 WinForms界面更新、简单的定时任务
System.Timers.Timer System.Timers 后台线程 服务端应用、非UI的周期性任务
System.Threading.Timer System.Threading 后台线程 高精度定时、需要更多控制权

二、System.Windows.Forms.Timer

🎯 核心特点

这是 WinForms 应用程序中最常用的定时器!

  • ✅ 运行在 UI 线程,可以直接操作界面控件

  • ✅ 精度较低(约 15-55ms)

  • ✅ 适合界面刷新、简单定时任务

  • ❌ 不适合需要高精度的场景

.net设计这个定时器的目的是为了方便程序员在Window Form中使用定时器。当一个System.Windows.Forms.Timer类被构造时,当前定时器会和当前线程进行关联 。而当计时器的计时达到后,一个定时器消息将被插入到当前线程的消息队列中。当前线程逐一处理消息中的所有消息,并一一派发给各自的处理方法。这样的机制和利用工作者进程定时有很大的区别,事实上,System.Windows.Forms.Timer类型并没有涉及多线程 的操作,定时器的设置、定时方法的执行都在同一个线程之上。

这就意味着System.Windows.Forms.Timer并不能准确计时,事实上,当消息阻塞时,定时器的误差将非常大 ,因为定时器消息只能等待在前面的所有消息处理完后才能得到处理。但是因为System.Windows.Forms.Timer类型的定时器并不涉及多线程的操作,因此是线程安全的,不会发生回调方法重入的问题。

使用步骤:

  1. System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();//实例化

  2. myTimer.Tick += new EventHandler(函数名); //给timer挂起事件

  3. myTimer.Enabled = true;//使timer可用

  4. myTimer.Interval = 1000; //设置时间间隔,以毫秒为单位,1000是1秒

  5. myTimer.Stop(); //如果要暂停计时则使用Stop()方法

  6. myTimer.Enabled = false;//若要停止使用timer,则使之不可用

cs 复制代码
//Winform自带的Timer控件使用
 
using System.Windows.Forms;
 
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            //初始化定时器
            Timer timer = new Timer();
            //定时器间隔1秒
            timer.Interval = 1000;
            //定时器触发事件,timer1_Tick是winform自带的Timer控件的方法
            timer.Tick += timer1_Tick;
            //定时器可用
            timer.Enabled = true;
            //启动定时器
            timer.Start();
        }
 
        /// <summary>
        /// winform自带的Timer定时器控件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            richTextBox1.Text += DateTime.Now.Second.ToString() + "\n";
            Console.WriteLine(richTextBox1.Text);
        }
    }

Tips:

  1. 在Winfrom中既可以使用Timer控件(这个控件也只是Tick时触发的方法等价于用户自定义的触发器方法,除此之外使用和自定义使用一样),也可以使用自定义的定时器方法

  2. 它的主要缺点是计时不精确,而且必须有消息循环,Console Application(控制台应用程序)无法使用。

三、System.Threading.Timer

🎯 核心特点

这是最高级的定时器,提供最多的控制权!

  • ✅ 最轻量级、最高效的定时器

  • ✅ 运行在 后台线程池

  • ✅ 精度最高(可达1ms级别)

  • ✅ 可以灵活地控制回调函数

  • ✅ 支持一次性和周期性执行

  • ⚠️ 使用相对复杂,需要手动管理资源

这个定时器类型的使用相对复杂,但同时它也是最优化的一个定时器类型。System.Threading.Timer的定时方法将被确定在工作者线程上执行 。所有的对象有一个线程控制,当下一个定时到达时,该线程会负责在线程中获得一个新的工作者线程,用以执行相应的回调方法。

虽然这个定时器是相对最优化的一个定时器类型,但是从其机制上来讲,其并不是线程安全的,可能会出现回调方法重入 的问题。解释下方法重入,是一个有关多线程编程的概念,意思大概是:程序中,多个线程同时运行时,就可能发生同一个方法被多个进程同时调用的情况。当这个方法中存在一些非线程安全的代码时,方法重入会斗志数据不一致的情况,这个非常严重的bug。

cs 复制代码
using System;
using System.Threading;

public class ThreadingTimerExample
{
    private System.Threading.Timer timer;

    public ThreadingTimerExample()
    {
        // 创建定时器
        // 参数1:回调函数
        // 参数2:回调函数的参数
        // 参数3:首次触发前的延迟时间(毫秒)
        // 参数4:后续触发的时间间隔(毫秒)
        timer = new System.Threading.Timer(
            TimerCallback,
            null,
            1000,  // 1秒后首次触发
            2000   // 之后每2秒触发一次
        );
    }

    // 定时器回调函数
    private void TimerCallback(object state)
    {
        Console.WriteLine($"定时器触发: {DateTime.Now}");
        
        // 执行定时任务
        DoWork();
    }

    private void DoWork()
    {
        // 执行具体任务
    }

    // 更改定时器参数
    public void ChangeTimer(int dueTime, int period)
    {
        timer.Change(dueTime, period);
    }

    // 停止定时器
    public void Stop()
    {
        timer.Change(Timeout.Infinite, Timeout.Infinite);
    }

    // 释放资源
    public void Dispose()
    {
        timer.Dispose();
    }
}

四、System.Timers.Timer

🎯 核心特点

  • ✅ 运行在 后台线程池,不阻塞UI

  • ✅ 精度比WinForms Timer高(约10-15ms)

  • ✅ 适合服务端应用、后台数据处理

  • ⚠️ 操作UI需要使用Invoke

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

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

cs 复制代码
using System;
using System.Timers;

public class TimerExample
{
    private System.Timers.Timer timer;

    public TimerExample()
    {
        // 创建定时器
        timer = new System.Timers.Timer();
        // 设置间隔(毫秒)
        timer.Interval = 1000; // 1秒
        // 绑定事件
        timer.Elapsed += Timer_Elapsed;
        // 设置是否重复触发
        timer.AutoReset = true; // true=重复,false=只触发一次
        // 启动定时器
        timer.Start();
    }

    // 定时器事件处理程序(运行在后台线程)
    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        // ⚠️ 注意:运行在后台线程,不能直接操作UI
        Console.WriteLine($"定时器触发: {DateTime.Now}");
        // 执行后台任务(如数据处理、日志记录等)
        ProcessData();
    }

    private void ProcessData()
    {
        // 这里可以执行耗时操作,不会阻塞UI
        // 模拟数据处理
        Thread.Sleep(500);
    }
    public void Stop()
    {
        timer.Stop();
        timer.Dispose();
    }
}

五、BackgroundWorker 组件

🎯 核心特点

BackgroundWorker 是 WinForms 中专门用于后台任务的组件!

  • ✅ 专为 WinForms 设计,简化后台任务编程

  • ✅ 自动处理线程同步,操作UI更简单

  • ✅ 支持进度报告(ProgressChanged事件)

  • ✅ 支持任务取消(CancellationPending)

  • ✅ 任务完成自动通知(RunWorkerCompleted事件)

相关推荐
CoderCodingNo2 小时前
【GESP】C++五级练习题 luogu-P1031 [NOIP 2002 提高组] 均分纸牌
开发语言·c++·算法
测试_AI_一辰2 小时前
项目实践笔记13:多用户事实碎片 Agent 的接口测试与约束设计
开发语言·人工智能·ai编程
twj_one3 小时前
java中23种设计模式
java·开发语言·设计模式
梵刹古音3 小时前
【C语言】 跳转语句
c语言·开发语言·算法
阿猿收手吧!3 小时前
【C++】C++模板特化:精准定制泛型逻辑
开发语言·c++·算法
ghie90903 小时前
MATLAB中编写不平衡磁拉力方程
开发语言·matlab
weixin_452159554 小时前
C++与Java性能对比
开发语言·c++·算法
会叫的恐龙4 小时前
C++ 核心知识点汇总(第一日)(输入输出与变量、类型转换)
开发语言·c++
2301_765703144 小时前
C++中的工厂模式实战
开发语言·c++·算法