【问题标题】:How to make timer fire in a recurring manner如何以重复的方式使计时器触发
【发布时间】:2013-12-02 15:20:18
【问题描述】:

我有一个计时器,希望在每个星期一下午 5 点到期。在测试应用程序时,一旦到达星期一下午 5 点,我的任务就会按预期被触发。

但是,当我将系统日期和时间更改为下一周下午 5 点时,任务不会触发。这是我的代码:

Timer timer = new Timer(callback, application, timeToEnd, TimeSpan.FromDays(7));

我感觉它与TimeSpan.FromDays(7) 部分有关。有什么想法吗?

【问题讨论】:

  • 你用的是哪个定时器?
  • @Servy - System.Threading.Timer

标签: c# .net windows multithreading timer


【解决方案1】:

这不是Timer 的好用处。您应该创建一个控制台应用程序来执行您想要的操作,然后使用 Windows Scheduler 或第 3 方调度工具对其进行调度。

否则,更安全的做法是将计时器设置为以 间隔(1 分钟?)运行并检查系统时钟以查看它是否需要运行(例如它在 5:00 的 1 分钟内?)

【讨论】:

  • 我同意你的观点,但这不是我的代码,因此我无法重写所有内容。
  • 您不必重写所有内容 - 只需创建一个控制台应用程序,该应用程序调用一次相关的现有代码并安排在所需时间运行。 Timer 旨在在 interval 上运行代码,而不是在指定的时间。但是,我添加了一些额外的可能性。
【解决方案2】:

你现在有麻烦了。我们要求框架在x days, y hours, z minutes 之后通知您。所以计时器会在你告诉它的时间之后触发。

我知道这不是正确的方法,但这会奏效。

SystemEvents.TimeChanged += SystemEvents_TimeChanged;

static void SystemEvents_TimeChanged(object sender, EventArgs e)
{
    timer.Dispose();//Dispose your previous timer
    SetTimerAgain();//Call the method which sets the timer again. you're done
}

我推荐“Windows 计划任务”,但由于某些原因你不能这样做,所以这是要走的路。

您还可以按照@giammin 的建议运行定期计时器。

TimerCallback callback = (state) =>
{      
    var now = DateTime.Now; 
    if(now.DayOfWeek == DayOfWeek.Monday 
     && now.TimeOfDay.Hours == 17 && now.TimeOfDay.Minutes == 0)
    {
        MyMethod();
    }
};

Timer timer = new Timer(callback, application, 0, 10000);//10seconds

使用后一种方法,您应该避免在同一天一次又一次地调用该方法。

【讨论】:

  • 我只是为了测试目的而更改系统时间 - 在部署环境中,系统时间不会更改。
  • 澄清一下——如果我不得不保留代码原样而不更改系统时间,定时器会在下周一触发吗?我只是更改系统日期和时间来尝试模拟一周过去,只是为了测试它
  • 是的,它应该可以正常工作。当您将时间准确设置为monday 5pm 时,您可能会遇到问题。那个时候它可能无法正常工作。否则它应该可以工作。
  • 感谢您的澄清!
  • @DotNET 是的,该机制不是测试该机制的合适方式。它会在一周内触发。更改系统时间根本不会影响它;无论如何它都会在一周内触发。
【解决方案3】:

没有一个计时器依赖于系统时间。

更改时钟不会影响System.Windows.Forms.TimerSystem.Timers.TimerSystem.Threading.Timer

如果您需要处理这些情况,您必须依靠SystemEvents.TimeChanged

否则您可以定期检查DateTime.Now.DayOfWeek == DayOfWeek .Monday

【讨论】:

  • 有趣。这可以解释它 - 但在这种情况下,Timer 类从哪里获得时间?因为它肯定基于系统时钟,因为我的 PC 时钟提前 5 分钟 - 并且计时器仍然在我的时钟下午 5 点触发
  • @DotNET 它使用处理器刻度而不是 Windows 日期。这是由于您如何使用 DateTime.Now 初始化计时器
  • 我明白了,感谢您的澄清。所以理论上我的代码没有问题,如果我不得不等待一周,任务应该再次触发?
  • @DotNET 是的,但最好检查 DateTime.Now 这么长时间而不是使用计时器,因为除了时间更改之外,可能还有夏令时
  • 感谢您的帮助,+1!
【解决方案4】:

如果您不想依赖诸如 Window Task Scheduler 之类的外部服务,您将不得不创建一个定期触发(比如每分钟)并检查当前时间的计时器,如果当前时间已过下一个过期时间它实际上执行了所需的操作(包括设置下一个过期时间)。

除非您在低功率设备上运行,否则每分钟执行一次时间检查应该不是问题。

将时钟提前一周是一种非常极端的措施,但夏令时也可以移动时钟,尤其是在虚拟机上,您可能会遇到一些意想不到的时钟漂移。这就是为什么在大多数时间定期检查当前时间比仅仅设置一个计时器在某个遥远的未来时间触发要好。

谈到夏令时,您需要处理时钟向后移动一小时的情况,以防您想在该时间间隔内执行活动。

【讨论】:

    【解决方案5】:

    如果您想要一个在特定时间触发的计时器,请使用Waitable Timer。不幸的是,.NET 库没有该计时器的包装器。前段时间我写了一篇文章。文章不再在线提供,但您可以从http://mischel.com/pubs/waitabletimer.zip下载源代码。

    也就是说,在我看来你拥有的是catnap program。按照其他人的建议去做,让它成为一个简单的控制台应用程序,您可以使用计划任务进行控制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      • 2015-09-01
      相关资源
      最近更新 更多