【发布时间】:2011-09-09 16:32:00
【问题描述】:
我有一个始终在运行的服务,它有一个计时器,可以在每天凌晨 2 点执行特定操作。
TimeSpan runTime = new TimeSpan(2, 0, 0); // 2 AM
TimeSpan timeToFirstRun = runTime - DateTime.Now.TimeOfDay;
if (timeToFirstRun.TotalHours < 0)
{
timeToFirstRun += TimeSpan.FromDays(1.0);
}
_dailyNodalRunTimer = new Timer(
RunNodalDailyBatch,
null,
timeToFirstRun,
TimeSpan.FromDays(1.0)); //repeat event daily
该初始化代码在服务首次启动时调用一次,过去几天我在 Timer 触发时记录了:
2011-05-21 02:00:01.580
2011-05-22 02:00:03.840
...
2011-05-31 02:00:25.227
2011-06-01 02:00:27.423
2011-06-02 02:00:29.847
您可以看到它每天漂移 2 秒,距离它应该发射的时间越来越远(凌晨 2 点)。
是我用错了还是这个定时器设计不准确?我可以每天重新创建计时器,或者让它以一些小的间隔触发并反复检查我是否要执行该操作,但这似乎有点 hacky。
编辑
我尝试使用 System.Timers.Timer,但似乎也有同样的问题。重置间隔是因为您无法像在 System.Threading.Timer 中那样在 System.Timers.Timer 中的第一个滴答声之前安排初始时间
int secondsInterval = 5;
double secondsUntilRunFirstRun = secondsInterval - (DateTime.Now.TimeOfDay.TotalSeconds % secondsInterval);
var timer = new System.Timers.Timer(secondsUntilRunFirstRun * 1000.0);
timer.AutoReset = true;
timer.Elapsed += (sender, e) =>
{
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff"));
if (timer.Interval != (secondsInterval * 1000.0))
timer.Interval = secondsInterval * 1000.0;
};
timer.Start();
产生以下时间,你可以看到它们是如何轻微漂移的:
06:47:40.020
06:47:45.035
06:47:50.051
...
06:49:40.215
06:49:45.223
06:49:50.232
所以我想最好的方法真的是在滴答处理程序中重新安排计时器?以下在约 15 毫秒内以固定间隔产生一个滴答声
double secondsUntilRunFirstRun = secondsInterval - (DateTime.Now.TimeOfDay.TotalSeconds % secondsInterval);
var timer = new System.Timers.Timer(secondsUntilRunFirstRun * 1000.0);
timer.AutoReset = false;
timer.Elapsed += (sender, e) =>
{
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff"));
timer.Interval = (secondsInterval - (DateTime.Now.TimeOfDay.TotalSeconds % secondsInterval)) * 1000.0;
};
timer.Start();
06:51:45.009
06:51:50.001
...
06:52:50.011
06:52:55.013
06:53:00.001
【问题讨论】:
-
函数需要2秒吗?
-
定时器只是启动事件,它真的要等待工作线程完成后再重新安排事件吗?我不确定该函数究竟需要多长时间,可能是 2 秒左右
-
使用windows计划任务不是更好吗。
标签: c# time windows-services timer