WinForms 中 Timer 只执行一次是因为默认不自动重启,需在 Tick 事件末尾调用 Start() 或避免 Stop();它绑定 UI 线程,不可用于 Console/.NET Core;后台任务应选 System.Threading.Timer 或 System.Timers.Timer。

Timer 在 WinForms 里为什么只执行一次就停了?
因为 System.Windows.Forms.Timer 默认不会自动重启,Enabled 设为 false 后,哪怕你没手动关,触发一次后也会自己熄火。常见于忘记在事件处理里重置或漏掉 Start()。
- 必须在
Tick事件末尾显式调用timer.Start()(如果之前被停过),或者更稳妥地——压根别关它,靠Enabled = true控制启停 - 不要在
Tick里直接Stop()+Dispose(),除非你真想彻底废掉这个定时器 - WinForms Timer 是单线程、UI 绑定的,不能在
Tick中做耗时操作(比如文件读写、HTTP 请求),否则界面会卡住
.NET Core / Console 程序该用哪个 Timer?
用 System.Threading.Timer 或 System.Timers.Timer,但别碰 System.Windows.Forms.Timer —— 它依赖 Windows 消息循环,在无 UI 环境下根本跑不起来,会静默失效。
-
System.Threading.Timer:轻量、回调在线程池线程上执行,适合后台任务;构造时传入callback、state、dueTime和period,注意period = 0表示只执行一次 -
System.Timers.Timer:有Elapsed事件,支持AutoReset(设为false就只触发一次),但事件回调默认也在线程池线程,跨线程更新 UI 要手动切回主线程(比如用Invoke) - 别在
using块里创建并运行Timer,它一出作用域就被 Dispose,定时逻辑立刻中断
定时精度不准、延迟严重怎么办?
所有 .NET Timer 都不是硬实时机制,底层依赖系统时钟节拍(Windows 默认约 15.6ms),设置 Interval = 1 毫秒毫无意义,实际最小稳定间隔通常在 10–50ms 区间。
- 高频率(SpinWait + 高精度计时器(如
Stopwatch)做轮询,但代价是 CPU 占用飙升 - 长时间运行后出现越来越大的漂移?检查是否在
Tick或回调里做了阻塞操作,导致下一次触发被延后;改用异步非阻塞方式(如await Task.Delay()配合循环)更可控 - 服务端长期运行程序(如 ASP.NET Core 后台服务),优先用
IHostedService+PeriodicTimer(.NET 6+),它基于ManualResetValueTaskSourceCore,延迟更低、资源更省
如何安全停止并释放 Timer?
直接 timer.Dispose() 不一定安全——如果回调正在执行中,Dispose() 会等它结束;而 timer.Stop() 只是暂停,不释放资源,对象还活着。
- 推荐模式:先
timer.Change(Timeout.Infinite, Timeout.Infinite)(对Threading.Timer)或timer.Stop()(对Timers.Timer),再Dispose() - 确保回调里没有访问已释放的资源(比如已
Close()的数据库连接),加null或IsDisposed检查 - 在
Form.Closing或服务StopAsync里清理 Timer,别等到 GC 来收——它可能永远等不到









