C#中IHostedService定时器无法重复触发LoadData方法问题
.NET Core 5 Timer仅首次执行的问题修复方案
问题根源
- Timer被垃圾回收:
StartAsync方法中声明的_timer是局部变量,方法执行完毕后没有被类实例持有引用,会被GC回收,导致后续定时触发失效。 - async void的隐患:
LoadData使用async void修饰,异步操作抛出的异常无法被正常捕获,一旦出现异常会直接终止Timer的后续触发;同时Timer无法等待异步回调完成,可能引发并发问题。
修复代码
1. 将Timer改为类字段,避免被GC回收
private System.Threading.Timer _timer; public Task StartAsync(CancellationToken stoppingToken) { // 注册应用停止时的Timer清理逻辑 stoppingToken.Register(() => _timer?.Change(Timeout.Infinite, 0)); _timer = new System.Threading.Timer(LoadData, null, TimeSpan.Zero, TimeSpan.FromMinutes(2)); return Task.CompletedTask; }
2. 替换async void为async Task并处理异常
// Timer回调用同步方法包装异步逻辑 private void LoadData(object state) { // 用_忽略返回值,避免编译器警告,同时确保异常被内部处理 _ = LoadDataAsync(state); } // 实际异步业务逻辑,用async Task保证异常可捕获 private async Task LoadDataAsync(object state) { try { var res = await _repository.GetAsync(); // ... 其他业务逻辑 } catch (Exception ex) { // 这里添加异常处理,比如写入日志,避免异常终止Timer } }
关键说明
- 类字段
_timer持有强引用,确保GC不会回收Timer实例,保证定时触发持续有效。 - 通过
stoppingToken注册清理逻辑,在应用停止时将Timer改为无限期等待,避免资源泄漏。 - 用
async Task替代async void,配合异常捕获,防止异步异常导致Timer停止运行。
内容的提问来源于stack exchange,提问作者Negin
相关产品推荐
相关产品推荐

