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

用 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 更健壮,但引入了依赖注入和宿主生命周期概念——如果你没在用 WebHost 或 HostBuilder,这条路走不通。
- 必须实现
StartAsync和StopAsync - 在
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();}
网奇英文商城外贸系统
网奇Eshop是一个带有国际化语言支持的系统,可以同时在一个页面上显示全球任何一种语言而没有任何障碍、任何乱码。在本系统中您可以发现,后台可以用任意一种语言对前台进行管理、录入而没有阻碍。而任何一个国家的浏览者也可以用他们的本国语言在你的网站上下订单、留言。用户可以通过后台随意设定软件语言,也就是说你可以用本软件开设简体中文、繁体中文与英文或者其他语言的网上商店。网奇Eshop系统全部版本都使用模
下载
遇到 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,或 Linuxsystemdservice - 要支持失败重试、依赖其他任务、可视化监控 → 上
Quartz.NET(注意它默认不持久化,加AdoJobStore才能存 DB) - 部署在多台服务器,但同一任务只能跑一次 → 需分布式锁(如 Redis +
RedLock)或 Quartz 的集群模式 - 只是每天凌晨跑个导出 → 直接用系统级计划任务(Windows Task Scheduler / Linux cron),C# 程序做成命令行工具即可
真正难的不是“怎么让代码隔段时间跑一次”,而是“怎么保证它在各种异常下依然可靠、可观测、可维护”。选最简单的方案起步,等痛点出现再升级。








