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

来源:这里教程网 时间:2026-02-21 17:37:13 作者:

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

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

它在后台线程池中运行,不会阻塞主线程,但要注意:回调函数里不能直接更新 UI(WinForms/WPF 需用

Invoke
);如果回调抛出未捕获异常,整个 Timer 会静默停止。

dueTime
是首次触发前的毫秒延迟(
TimeSpan.Zero
表示立即执行)
period
是后续重复间隔(设为
Timeout.Infinite
就只执行一次)
务必保存对
Timer
实例的引用,否则可能被 GC 回收导致任务意外终止
private Timer _timer;
<p>public void StartCheck()
{
<em>timer = new Timer(</em> => {
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;
<pre class='brush:php;toolbar:false;'>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<checkstatusservice>()</checkstatusservice>
注册
在 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# 程序做成命令行工具即可

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

相关推荐