C# 定时任务实现方法 C#如何使用Timer实现定时任务

2次阅读

system.threading.timer最轻量但需手动释放资源且回调不能操作ui控件;system.timers.timer支持事件模型和线程封送;system.windows.forms.timer仅限winforms ui线程;task.delay适合异步定时任务。

C# 定时任务实现方法 C#如何使用Timer实现定时任务

System.Threading.Timer 是最轻量的定时触发方式

它不依赖 UI 线程,适合后台服务、控制台程序中执行无界面逻辑。但回调在 ThreadPool 线程上运行,不能直接操作 WinForms/wpf 控件,且没有内置的“暂停/继续”控制。

  • 构造时需传入 TimerCallback 委托、状态对象、首次延迟(毫秒)、周期间隔(毫秒)
  • 若希望只执行一次,把周期设为 Timeout.Infinite
  • 必须手动调用 Dispose() 释放资源,否则可能造成内存泄漏或后台线程持续运行
  • 回调中发生未捕获异常会终止该次执行,但不会影响后续触发——这点容易被忽略,建议包裹 try/catch
var timer = new System.Threading.Timer(state => {     try     {         Console.WriteLine($"Tick at {DateTime.Now:HH:mm:ss}");     }     catch (Exception ex)     {         Console.WriteLine($"Error in timer callback: {ex.Message}");     } }, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5));

System.Timers.Timer 更适合需要事件模型的场景

封装System.Threading.Timer,提供 Elapsed 事件,支持 AutoResetEnabled 控制,并可设置 SynchronizingObject 将回调封送到指定线程(如 Windows Forms 的 UI 线程)。

  • 默认 AutoReset = true,即周期性触发;设为 false 则只触发一次
  • Enabled = false 可暂停,设回 true 即恢复,比手动 Change() 更直观
  • 在 WinForms 中可赋值 timer.SynchronizingObject = this;,使 Elapsed 回调自动进入 UI 线程
  • 注意:未调用 Stop() 或设 Enabled = false 前,对象被 GC 回收时不会自动停掉定时器
var timer = new System.Timers.Timer(3000); timer.Elapsed += (s, e) => Console.WriteLine($"Fired at {e.SignalTime:HH:mm:ss}"); timer.AutoReset = true; timer.Enabled = true;

System.Windows.Forms.Timer 仅限 WinForms UI 线程使用

它是唯一基于消息循环的定时器,所有回调都在创建它的 UI 线程中执行,天然线程安全,但**不能用于控制台、WPF 或后台服务**。一旦窗体关闭或线程退出,它自动失效。

  • 间隔单位是毫秒,最大值约 2^31−1(约 24.8 天),但实际建议不超过几分钟,避免精度下降
  • 启用只需设置 Interval 后调用 Start();禁用用 Stop()
  • 如果在回调中执行耗时操作(如网络请求、文件读写),会阻塞 UI 线程,导致界面卡顿——这是最常见的误用点
var timer = new System.Windows.Forms.Timer(); timer.Interval = 2000; timer.Tick += (s, e) => label1.Text = DateTime.Now.ToString("HH:mm:ss"); timer.Start();

Task.Run + Task.Delay 组合更适合异步定时逻辑

当你的定时任务本质是“每隔 N 秒做一次异步操作”(如调用 http API、写数据库),用 Task.Delay 配合循环比传统 Timer 更自然,也更容易取消和错误传播。

  • 必须配合 CancellationToken 实现可控停止,否则 while(true) 会永远挂住
  • 每次循环开头先 await Task.Delay(..., token),再执行业务逻辑,避免因前次耗时过长导致
  • 异常会抛出到外层 Task,可用 await task 捕获,或用 task.ContinueWith(..., TaskContinuationOptions.OnlyOnFaulted)
var cts = new CancellationTokenSource(); var task = Task.Run(async () => {     while (!cts.Token.IsCancellationRequested)     {         try         {             await Task.Delay(5000, cts.Token);             await DoAsyncWork(); // e.g., HttpClient.GetAsync(...)         }         catch (OperationCanceledException)         {             break;         }         catch (Exception ex)         {             Console.WriteLine($"Async job failed: {ex.Message}");         }     } }, cts.Token);

定时器的“准时性”受系统调度、GC、线程池负载影响,不要假设它能精确到毫秒级;真正对精度敏感的任务(如音视频同步、工业控制)应使用更高优先级线程或专用硬件方案。

text=ZqhQzanResources