简体   繁体   English

C#Timer on Elapsed Time不调用方法

[英]C# Timer on Elapsed Time does not call method

The below class is from a .Net Windows Service. 以下类来自.Net Windows服务。 The method DoSomeDatabaseStuff takes 10 minutes when it starts the first time but when the time is elapsed this method does not get called again. 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();
        }
}

There are lots of serious problems in this code: 此代码中存在许多严重问题:

  • If the Start method is meant to be the OnStart() method of the service then you can never get the service started. 如果Start方法是服务的OnStart()方法,那么您永远无法启动服务。 OnStart() must complete in less than 30 seconds. OnStart()必须在30秒内完成。 Just initialize the timer and don't do anything else 只需初始化计时器,不要做任何其他事情
  • Creating another Timer in the Elapsed event handler is a grave mistake. 在Elapsed事件处理程序中创建另一个Timer是一个严重的错误。 Your event handler will now run twice. 您的事件处理程序现在将运行两次。 After the second time it is called it will run thrice. 在第二次调用之后,它将运行三次。 Etcetera. 等等。
  • Your test program does not test the way the code will run in a service. 您的测试程序不会测试代码在服务中运行的方式。 The Elapsed event handler will never run since the test will have been completed before your event handler can run. Elapsed事件处理程序将永远不会运行,因为测试将在您的事件处理程序运行之前完成。 Which explains your observation 这解释了你的观察
  • You must use try/catch in the Elapsed event handler. 必须在Elapsed事件处理程序中使用try / catch。 If you don't then any exception will be swallowed without a diagnostic. 如果不这样做,那么在没有诊断的情况下将吞下任何异常。 The System.Timers.Timer class is nasty like that, favor System.Threading.Timer instead Also explains your observation System.Timers.Timer类很讨厌,喜欢System.Threading.Timer而且还解释了你的观察
  • You must ensure that your event handler is re-entrant. 必须确保您的事件处理程序是可重入的。 It can run again when the previous invocation of the event handler is still busy, this will happen when the task takes more than a minute. 它可以在前一次调用事件处理程序仍然繁忙时再次运行,这将在任务超过一分钟时发生。 This very rarely comes to a good end. 这很少有好结果。 Setting AutoReset = false is a simple way to avoid this re-entrancy, start the timer back up at the end of the event handler to get it to repeat. 设置AutoReset = false是一种避免此重入的简单方法,在事件处理程序结束时启动计时器以使其重复。

I use the System.Threading.Timer in windows-services. 我在windows-services中使用System.Threading.Timer

Maybe this solves also your issue since others have also problems with the System.Timers.Timer in windows-services: "What I've found is that System.Timers.Timer just doesn't work in my Windows Service application. Therefore I've switched over to System.Threading.Timer " 也许这也解决了你的问题,因为其他人也在Windows服务中的System.Timers.Timer问题: “我发现System.Timers.Timer在我的Windows服务应用程序中不起作用。所以我' ve切换到System.Threading.Timer

See: Windows Service System.Timers.Timer not firing 请参阅: Windows Service 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();
}

Your program ends before timer could run. 您的程序在计时器运行之前结束。 Timer is working in background thread witch is terminated when the main thread stops. Timer正在后台线程中工作当主线程停止时终止。

try 尝试

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

Instead of creating a new timer every time, try setting the OnTimeout handler to: 不要每次都创建一个新的计时器,而是尝试将OnTimeout处理程序设置为:

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

similarly with the method Start(). 与方法Start()类似。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM