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

System.Threading.Timer运行异常问题排查求助

问题分析与解决方案

咱们直接说核心问题:你的定时器出现输出丢失,根源在于回调函数的长时间阻塞和错误的时间控制逻辑,具体拆解来看:

1. System.Threading.Timer的工作机制导致触发丢失

System.Threading.Timer是靠线程池线程执行回调的,它有个关键规则:如果上一次回调还在运行,当下一次触发时间到了的时候,系统会直接跳过这次触发(不会排队等待)。

你的代码里,TimerCallback里用Thread.Sleep(10000)模拟了10秒的长耗时操作,但定时器的间隔却设成了1000ms(1秒)。这意味着每次回调会霸占线程池线程10秒,在这10秒里,定时器原本该触发的10次回调全被跳过了。等回调结束后,定时器才会继续按间隔触发,但此时你的countDown已经少减了好多次,自然会出现时间跳变、漏输出的情况。

2. 基于计数的时间控制逻辑完全不可靠

你用countDown从60递减到0来触发每分钟输出,这个逻辑完全依赖回调被精准执行60次(每次间隔1秒)。可一旦回调被阻塞或跳过,countDown的递减节奏就乱了——要么实际过了1分钟但countDown还没到0,要么countDown到0时实际时间已经超了1分钟,甚至直接跳过该输出的时间点。


修正后的代码方案

我给你两种修复思路,按需选择:

方案一:直接用每分钟间隔的定时器,耗时操作异步处理

适合不需要每秒执行额外逻辑,只需要每分钟输出一次的场景:

class Program
{
    static Timer m_Timer;

    static void Main(string[] args)
    {
        // 配置定时器:立即执行第一次,之后每隔60秒执行一次
        m_Timer = new Timer(TimerCallback, null, 0, 60000);
        Console.WriteLine("定时器已启动,按任意键退出...");
        Console.ReadKey();
        // 记得释放定时器资源
        m_Timer.Dispose();
    }

    static void TimerCallback(Object o)
    {
        Console.WriteLine(" ===>>>>>>" + DateTime.Now.ToString());
        // 把耗时操作丢到异步任务里,绝不阻塞回调线程
        Task.Run(() =>
        {
            // 模拟长时间运行的代码
            Thread.Sleep(10000);
            Console.WriteLine("耗时操作完成:" + DateTime.Now.ToString());
        });
    }
}

方案二:保留1秒间隔,基于时间差判断输出

适合需要每秒执行其他逻辑,同时每分钟输出一次的场景:

class Program
{
    static Timer m_Timer;
    static DateTime _lastPrintTime;

    static void Main(string[] args)
    {
        _lastPrintTime = DateTime.Now;
        m_Timer = new Timer(TimerCallback, null, 0, 1000);
        Console.WriteLine("定时器已启动,按任意键退出...");
        Console.ReadKey();
        m_Timer.Dispose();
    }

    static void TimerCallback(Object o)
    {
        var now = DateTime.Now;
        // 检查距离上次打印是否过了1分钟(允许少量误差)
        if (now.Subtract(_lastPrintTime).TotalMinutes >= 1)
        {
            Console.WriteLine(" ===>>>>>>" + now.ToString());
            _lastPrintTime = now;
        }

        // 耗时操作异步处理,不影响定时器触发
        Task.Run(() =>
        {
            Thread.Sleep(10000);
        });
    }
}

额外提醒

  • 绝对不要在System.Threading.Timer的回调里做长时间同步操作,线程池线程是共享资源,阻塞会拖垮其他依赖线程池的功能。
  • 如果你的耗时操作必须保证每次触发都被处理(不能跳过),可以考虑用System.Timers.Timer并设置AutoReset = false,在回调结束后手动重置定时器,同时也要异步处理耗时逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:05:38