c# 如何实现一个定时任务

3次阅读

System.Threading.Timer 适合轻量级单机定时任务,IHostedService 适用于。NET Core 后台服务,超出现有能力时应升级为 Windows 服务、Quartz.NET 或系统计划任务。

c# 如何实现一个定时任务

System.Threading.Timer 实现轻量级定时任务

适合单次延迟执行、周期性简单操作(比如每 5 秒检查一次状态),不依赖外部服务,也不需要持久化或跨进程调度。

它在后台线程池中运行,不会阻塞主线程,但要注意:回调函数 里不能直接更新 UI(WinForms/WPF 需用 Invoke);如果回调抛出未捕获异常,整个 Timer 会静默停止。

  • dueTime 是首次触发前的毫秒延迟(TimeSpan.Zero 表示立即执行)
  • period 是后续重复间隔(设为 Timeout.Infinite 就只执行一次)
  • 务必保存对 Timer 实例的引用,否则可能被 GC 回收导致任务意外终止
private Timer _timer; 

public void StartCheck() { timer = new Timer( => {Console.WriteLine($"Tick at {DateTime.Now:HH:mm:ss}"); // 注意:这里不能直接调用 WinForms 的 this.Text = …… }, null, TimeSpan.Zero, TimeSpan.FromSeconds(5)); }

Microsoft.Extensions.Hosting.IHostedService 做后台服务级定时任务

适用于 .NET Core / .NET 5+ 的 Web API 或后台服务项目,配合 DI 容器管理生命周期,支持优雅关闭(比如正在执行的任务可等待完成)。

比裸用 Timer 更健壮,但引入了依赖注入和宿主生命周期概念——如果你没在用 WebHostHostBuilder,这条路走不通。

  • 必须实现 StartAsyncStopAsync
  • StartAsync 中启动 Timer,并在 StopAsync 中调用 _timer?.Change(Timeout.Infinite, 0) 停止它
  • 别在 StopAsync 里用 await _timer?.DisposeAsync() —— Timer 不支持异步释放
public class CheckStatusService : IHostedService, IDisposable {private Timer _timer; 
public Task StartAsync(CancellationToken cancellationToken) {_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));     return Task.CompletedTask; }  private void DoWork(object state) => Console.WriteLine("Checking……");  public Task StopAsync(CancellationToken cancellationToken) {_timer?.Change(Timeout.Infinite, 0);     return Task.CompletedTask; }  public void Dispose() => _timer?.Dispose();

}

遇到 ObjectDisposedException 或任务突然不执行?检查这几点

这是最常踩的坑:任务看似启动了,跑几次就停,或者一关程序就报 Cannot access a disposed object

  • 确认 Timer 实例是类字段(private Timer _timer),不是局部变量
  • 确认没有在回调里调用了 _timer.Dispose()_timer?.Dispose() —— 这会导致后续触发失败
  • 如果用了 IHostedService,确保已通过 services.AddHostedService() 注册
  • 在 ASP.NET Core 中,不要在 Controller 里 new 一个 Timer —— Controller 实例生命周期短,Timer 很快被回收

什么时候该换方案?

当需求超出内存内定时能力时,就得换路子:

  • 需要机器重启后继续运行 → 用 Windows 服务 + System.ServiceProcess.ServiceBase,或 Linux systemd service
  • 要支持失败重试、依赖其他任务、可视化监控 → 上 Quartz.NET(注意它默认不持久化,加 AdoJobStore 才能存 DB)
  • 部署在多台服务器,但同一任务只能跑一次 → 需分布式锁(如 Redis + RedLock)或 Quartz 的集群模式
  • 只是每天凌晨跑个导出 → 直接用系统级计划任务(Windows Task Scheduler / Linux cron),C# 程序做成命令行 工具 即可

真正难的不是“怎么让代码隔段时间跑一次”,而是“怎么保证它在各种异常下依然可靠、可观测、可维护”。选最简单的方案起步,等痛点出现再升级。

星耀云
版权声明:本站原创文章,由 星耀云 2026-01-08发表,共计2031字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。