You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

System.Threading.Timer是否需等待上一回调完成才触发新回调?

问题解答

1. 关于Timer触发行为的官方说明

System.Threading.Timer的触发逻辑在官方文档的类备注章节有明确记载:

  • 计时器设定的周期间隔,是从上一次回调被加入线程池工作队列的时间点开始计算,而非上一次回调执行完成的时间点。
  • 只要间隔到期,无论上一次回调是否执行完毕,新的回调都会被排入线程池队列等待执行。
  • 示例中使用async void作为回调会进一步放大这个现象:Timer本身不感知异步等待逻辑,async void方法在执行到第一个await时就会向调用方返回,Timer会直接认为本次回调已经执行结束,完全不会等待await后续的逻辑,因此才会出现每秒都有新回调启动、完全等不到10秒延迟结束的输出。

2. 等待上一次回调完成再触发的实现方式

.NET 没有内置开箱即用的、自动规避重入的System.Threading.Timer配置,你可以根据自己使用的.NET版本选以下两种实现方案,都能完全符合「上一次执行完成后,再等指定间隔触发下一次」的预期:

方案1:手动调度Timer(全版本通用)

初始化Timer时将周期参数设为Timeout.InfiniteTimeSpan,让Timer只触发第一次回调;每次回调的全部逻辑(包括异步等待部分)执行完成后,手动调用Change方法调度下一次触发,从根源上避免重入。
示例代码:

// 初始化时period设为无限超时,仅触发第一次
var timer = new Timer(TimerCallback, null, TimeSpan.Zero, Timeout.InfiniteTimeSpan);
static int i = 0;
async Task TimerCallback(object state)
{
    i++;
    Console.WriteLine($"method {i} started");
    try
    {
        // 实际业务逻辑
        await Task.Delay(10000);
        Console.WriteLine($"method {i} finished");
    }
    finally
    {
        // 无论业务逻辑成功还是抛异常,都调度下一次执行,避免计时器意外停止
        timer.Change(TimeSpan.FromSeconds(1), Timeout.InfiniteTimeSpan);
    }
}

注意不要使用async void作为Timer回调,否则回调中抛出的未处理异常会直接终止进程,也无法被全局异常捕获。

方案2:使用PeriodicTimer(.NET 6+ 推荐)

.NET 6 新增的PeriodicTimer是专门为异步场景设计的计时器,天然规避重入问题:它没有自动回调机制,需要在代码中主动等待下一个触发信号,执行完业务逻辑后再进入下一轮等待,逻辑更简洁也不容易出错。
示例代码:

var periodicTimer = new PeriodicTimer(TimeSpan.FromSeconds(1));
// 启动计时器循环
_ = RunTimerAsync(periodicTimer);

async Task RunTimerAsync(PeriodicTimer pt)
{
    int i = 0;
    // 等待下一次触发信号,到点才执行逻辑,执行完再回到等待状态
    while (await pt.WaitForNextTickAsync())
    {
        i++;
        Console.WriteLine($"method {i} started");
        await Task.Delay(10000);
        Console.WriteLine($"method {i} finished");
    }
}

不推荐用锁/信号量包裹回调的方式做重入控制,这种方式会让超过间隔时间到达的回调在线程池队列里排队,既浪费线程池资源,也做不到「执行完再等固定间隔」的效果。


内容的提问来源于stack exchange,提问作者meJustAndrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 18:22:17