【发布时间】:2010-11-26 01:04:37
【问题描述】:
我有一个 Windows 服务处理由 System.Timers.Timer 触发的事件。 我想将该计时器的间隔设置为 3 个月。
System.Timers.Timer 的 Interval 属性是以毫秒为单位的 Int32,而 Int32.MaxValue 以毫秒为单位小于 3 个月。
我该怎么办?
【问题讨论】:
我有一个 Windows 服务处理由 System.Timers.Timer 触发的事件。 我想将该计时器的间隔设置为 3 个月。
System.Timers.Timer 的 Interval 属性是以毫秒为单位的 Int32,而 Int32.MaxValue 以毫秒为单位小于 3 个月。
我该怎么办?
【问题讨论】:
遇到了同样的问题,只是它是一个通用系统,可以以完全可调的时间间隔(从毫秒到几个月)做同样的事情。嗯,是应该。事实证明,因为这个原因,它确实在大于 24.8 天的间隔上搞砸了。
就我而言,“重新考虑方法”是不可能的,因为它只是更大的 Windows 服务系统的一个小问题子案例。
解决方案相当简单,但请注意我有一个辅助系统,它为我提供了下一次执行为DateTime;计时器的工作只是将其与实际执行任务相匹配,因此它只需从中减去DateTime.Now 即可计算出间隔。
在这种情况下,我需要做的就是在我的计时器对象旁边保留一个溢出布尔值,并在根据Int32.MaxValue 检查该间隔时设置它:
private Timer _timer;
private Boolean _overflow;
private void QueueNextTime(DateTime thisTime)
{
TimeSpan interval = this.GetNextRunTime(thisTime) - DateTime.Now;
Int64 intervalInt = (Int64)((interval.TotalMilliseconds <= 0) ? 1 : interval.TotalMilliseconds);
// If interval greater than Int32.MaxValue, set the boolean to skip the next run. The interval will be topped at Int32.MaxValue.
// The TimerElapsed function will call this function again anyway, so no need to store any information on how much is left.
// It'll just repeat until the overflow status is 'false'.
this._overflow = intervalInt > Int32.MaxValue;
this._timer.Interval = Math.Min(intervalInt, Int32.MaxValue);
this._timer.Start();
}
// The function linked to _timer.Elapsed
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
this._timer.Stop();
if (this._overflow)
{
QueueNextTime(e.SignalTime);
return;
}
// Execute tasks
// ...
// ...
// schedule next execution
QueueNextTime(e.SignalTime);
}
当然,这是简化的;真实系统有 try/catch 和一个系统,可以根据外部停止命令中止。但这就是它的要点。
【讨论】:
您会重新考虑您的设计。存储您下次要执行事件的时间(例如注册表、文件、数据库等),然后定期唤醒以检查该时间是否已过。即使您可以将 System.Timers.Timer 设置为 3 个月,系统也可能会在计时器关闭之前重新启动,并且您会丢失您的事件。
另一种选择是使用由 Windows 调度程序执行的调度作业。它将运行一个小程序,向您的服务发送一条消息,说明事件已发生。与定期醒来检查 3 个月是否已过相比,这将减少资源密集型(尽管更复杂)。
【讨论】:
我会使用 Quartz.net - 开源企业作业调度器 - http://quartznet.sourceforge.net/
您可以使用类似 CRON 的语法 - http://quartznet.sourceforge.net/tutorial/lesson_6.html 并且您可以轻松地将相关的工作状态存储到数据库中(以防机器死机)-http://quartznet.sourceforge.net/tutorial/lesson_9.html,还有更多用处。
我已经在几个生产系统上使用过 Quartz.net,据我所知,这些进程今天仍在运行 :)
为什么不使用 System.Timer - http://quartznet.sourceforge.net/faq.html#whynottimer
祝你好运!
【讨论】:
您不能连续运行您的电脑 3 个月。如果应用程序关闭,计时器也将关闭。在重新启动应用程序时,计时器会从头开始重新启动。
如果您想每隔 3 个月触发一次事件,您必须保留有关退出应用程序时计时器经过的总时间的信息。
更新
因此,您必须将间隔划分为某些部分,并在每个时间段上设置一个计数器并增加它。在每个时间段中检查它,直到达到 3 个月。
例如
int interval = 10 * 24 * 60 * 60 * 1000; // Time interval for 10 days
int counter = 0;
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
counter++;
if (counter == 9)
{
//do your task for 3 months
//since counter increments 9 times at interval of 10 days
//so 9*10=90 days i.e. nearly equal to 3 months
counter = 0;
}
}
【讨论】:
我将创建一个 exe 应用程序并作为计划的 Windows 任务的一部分运行。
【讨论】: