2

下面的课程来自 .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();
        }
}
4

4 回答 4

6

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

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

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

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

请参阅: Windows 服务 System.Timers.Timer 未触发

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();
}
于 2013-09-13T12:34:57.180 回答
2

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

尝试

static void Main(string[] args)
{
    Test t = new Test();
    t.Start();
    Console.ReadLine();
}
于 2013-09-13T12:36:13.747 回答
1

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

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

与 Start() 方法类似。

于 2013-09-13T12:35:50.543 回答