使用C#,.NET Framework 4.0。 我有3个TimeSpan对象设置为20分钟,30分钟,45分钟。我想让Timer只在确切的分钟间隔内执行,无论何时实际启动任何计时器。 我需要定时器触发看起来像这样(每小时):
timerA 1:00
timerB 1:00
timerA 1:20
timerB 1:30
timerA 1:40
timerC 1:45
timerA 2:00
timerB 2:00
timerA 2:20
timerB 2:30
timerA 2:40
timerC 2:45
我认为Waitable计时器是正确的举动,但由于缺乏简单的例子,我猜不是。获得此功能的最佳方法是什么(如果可能的话,我希望避免时钟漂移,但我现在急需任何事情)?我没有和Waitable结婚。我也明白,timerC只能每小时运行一次,这很好,因为它设置为仅在每小时的第45分钟运行。
注意 - 我还没准备好使用Quartz.NET。
感谢。
答案 0 :(得分:1)
我能得到的最接近的是在目标时间'爬行',使用等待,(睡眠(),超时事件,一些线程计时器或经典'主线程窗口计时器),设置为数字的一半“现在”和目标时间之间的毫秒数,由实时时钟计算得出。如果剩余的ms大于某个限制(例如500),则重新计算剩余的ms并再次等待。当剩余的ms低于限制时,开始循环实时时钟直到达到或超过目标,然后调用TimeSpan对象的timeout()方法。
您可以将TimeSpan对象放在超时时间排序队列中,这样您只需要一个等待。如果您遇到TimeSpan事件经常“同时”发生的情况,这可能更准确,因为目标时间接近时只有一个线程循环。
RGDS, 马丁
答案 1 :(得分:1)
我认为这将为您完成工作:
static void Main(string[] args)
{
StartTimer(TimeSpan.FromMinutes(20.0), "TimerA", true);
StartTimer(TimeSpan.FromMinutes(30.0), "TimerB", true);
StartTimer(TimeSpan.FromMinutes(45.0), "TimerC", true);
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
启动计时器功能启动计时器并将其返回(如果需要参考)。这里的关键是你给它定时器名称,你告诉它你是否要将计时器与整个小时对齐。如果您不想与整个小时对齐,则计时器将立即以指定的频率启动。
public static Timer StartTimer(TimeSpan frequency, string timerName, bool alignToHour)
{
if (alignToHour)
{
return new Timer(OnTimerTick, timerName, ComputeDelay(frequency), frequency);
}
else
{
return new Timer(OnTimerTick, timerName, TimeSpan.Zero, frequency);
}
}
计时器滴答时将触发的函数。
public static void OnTimerTick(object state)
{
Console.WriteLine((string)state + " " + DateTime.Now.ToString("H:mm"));
}
此方法计算如果计时器必须在整个小时内对齐时所需的延迟。它仅在频率小于一小时或超过一分钟时有效。
public static TimeSpan ComputeDelay(TimeSpan frequency)
{
if (frequency > TimeSpan.FromHours(1.0) ||
frequency < TimeSpan.FromMinutes(1.0))
{
throw new ArgumentException(
"The frequency cannot be more than one hour or less than one minute!");
}
return frequency - TimeSpan.FromMinutes(DateTime.Now.Minute % frequency.Minutes);
}
注意:在您的示例中,您以1小时的频率运行45分钟计时器,但您分别在20和30分钟的频率上运行20分钟和30分钟的计时器。我的代码在1小时频率下不能使用45分钟计时器,但它可以在各自频率上使用20,30和45分钟计时器。我不确定你的例子是否错误,但如果没有错,那么我认为你应该能够从这里找出如何处理这个差异。