已用时间上的 C# 计时器不调用方法

本文关键字:调用 方法 计时器 时间上 | 更新日期: 2023-09-27 18:31:22

下面的类来自.Net Windows服务。方法DoSomeDatabaseStuff在第一次启动时需要10分钟,但是当时间经过时,此方法不会再次被调用。

public class Test
{
        public void Start()
        {
            DoSomeDatabaseStuff();
            _oTimer = new Timer(60000);
            _oTimer.Elapsed += OnTimeout;
            _oTimer.AutoReset = true;
            _oTimer.Start();
        }
        private void OnTimeout(object source, ElapsedEventArgs e)
        {
            DoSomeDatabaseStuff();
            _oTimer = new Timer(60000);
            _oTimer.Elapsed += OnTimeout;
            _oTimer.AutoReset = true;
            _oTimer.Start();
        }
}

已用时间上的 C# 计时器不调用方法

这段代码中有很多严重的问题:

    如果 Start 方法
  • 旨在成为服务的 OnStart() 方法,那么您永远无法启动该服务。 OnStart() 必须在 30 秒内完成。 只需初始化计时器,无需执行任何其他操作
  • 在已用事件处理程序中创建另一个计时器是一个严重的错误。 事件处理程序现在将运行两次。 第二次调用后,它将运行三次。 诸如此类。
  • 测试
  • 程序不会测试代码在服务中的运行方式。 已用事件处理程序永远不会运行,因为在事件处理程序可以运行之前,测试已经完成。 这解释了你的观察
  • 必须在已用事件处理程序中使用 try/catch。 如果您不这样做,那么任何异常都将在没有诊断的情况下被吞下。 System.Timers.Timer 类就是这样讨厌的,请改用 System.Threading.Timer 还解释了您的观察
  • 结果
  • 必须确保事件处理程序是可重入的。 当事件处理程序的先前调用仍然繁忙时,它可以再次运行,当任务花费超过一分钟时,就会发生这种情况。 这很少有好的结局。 设置 AutoReset = false 是避免此重入的简单方法,在事件处理程序结束时启动计时器备份以使其重复。

我在Windows服务中使用System.Threading.Timer

也许这也解决了你的问题,因为其他人也对Windows服务中的System.Timers.Timer有问题:"我发现System.Timers.Timer在我的Windows服务应用程序中不起作用。因此,我已切换到System.Threading.Timer"

请参阅:Windows Service System.Timers.Timer not trigger

private void InitService()
{
    //starts immediately, interval is in TimeSpan 
    this._oTimer = new System.Threading.Timer(
        OnTimeout,
        null, 
        TimeSpan.Zero,
        TimeSpan.FromMinutes(10)
    );
}
protected override void OnStart(string[] args)
{
    InitService();
}
protected override void OnStop()
{
    this._oTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
}
private void ImportTimer_Elapsed(Object state)
{
    DoSomeDatabaseStuff();
}

程序在计时器运行之前结束。 Timer在后台线程中工作,当主线程停止时,女巫将终止。

尝试

static void Main(string[] args)
{
    Test t = new Test();
    t.Start();
    Console.ReadLine();
}

不要每次都创建新的计时器,而是尝试将 OnTimeout 处理程序设置为:

_oTimer.Stop();
DoSomeDatabaseStuff();
_oTimer.Start();

与方法 Start() 类似。