c# . net 2线程.定时器-时间漂移

本文关键字:时间 漂移 定时器 线程 net | 更新日期: 2023-09-27 18:17:16

我有一个服务使用的dll。它的基本工作是每隔X分钟运行一次,并执行一些系统检查。在我的dll中,我有一个顶级类,声明了一个System.threading.timer和一个Timercallback。类的构造函数用我的线程函数初始化timerCallback。在我的"Onstart"处理程序中,我用timercallback初始化计时器,并设置下一次触发时间和间隔时间。我的情况是每10分钟一次。通常,在这些10分钟的检查中没有什么可做的,但服务每天至少在设定的时间执行一次操作。

我的问题是:我发现在测试过程中,每天执行每日检查的时间慢慢地偏离了期望的开始时间8.30。在大约20多天的时间里,我的时间从08.30到08.31.35不等。它每天漂移约4 - 6秒。

我的问题:有谁知道为什么时间像这样流逝,我怎么能让它坚持它的分配时间?

谢谢

c# . net 2线程.定时器-时间漂移

时间"漂移"是因为计时器不那么精确。如果您需要尽可能地按照一定的间隔运行代码,您可以这样做:

public void MyTimerCallback(object something) {
    var now = DateTime.UtcNow;
    var shouldProbablyHaveRun = new DateTime(
        now.Year, now.Month, now.Day,
        now.Hour, now.Minute - (now.Minute % 10), 0);
    var nextRun = shouldProbablyHaveRun.AddMinutes(10.0);
    // Do stuff here!
    var diff = nextRun - DateTime.UtcNow;
    timer.Change(diff, new TimeSpan(-1));
}

…假设您使用的是System.Threading.Timer实例。如果您使用其他类型的定时器(有几种!),请修改示例。

为什么不每分钟检查一次是否需要执行该操作呢?

ie:

if (DateTime.Now.Minute % 10) == 0 

它需要有限的时间来完成您在计时器方法处理程序中所做的操作,因此它不会每10分钟到秒发生一次,这是有道理的,特别是如果您在执行检查等操作后安排下一次唤醒。如果你已经在检查是否该做这件事了,你应该让你的计时器更频繁地触发,以满足你需要的解决方案,并相信你的检查,当它应该执行某些事情,以确保它做了。您可能需要某种持久性来确保它不会执行两次(如果这很重要的话),以防发生关闭/重新启动并且知道它是否已经运行的状态不在内存中。

我的看法是:

while ((DateTime.Now - lastRunTime).TotalSeconds < 600)
     CurrentThread.Sleep(1000);

或者只是注册一个Windows计时器并执行响应事件/回调

public static void Main()
{
    System.Timers.Timer aTimer = new System.Timers.Timer();
    aTimer.Elapsed+=new ElapsedEventHandler(OnTimedEvent);
    // Set the Interval to 600 seconds.
    aTimer.Interval=600000;
    aTimer.Enabled=true;
    Console.WriteLine("Press ''q'' to quit the sample.");
    while(Console.Read()!='q');
}
// Specify what you want to happen when the Elapsed event is raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    Console.WriteLine("10 minutes passed!");
}

计时器不是精确的,只是近似的。不要使用"只增加10分钟"的逻辑。每次计时器触发时,你都需要检查时间偏差并进行调整。

。如果你说"在10分钟内叫醒我",它在10分1秒内叫醒你,那么下一个计时器应该是9分59秒,而不是10分钟。

同时,你想在你的逻辑结束时分配你的下一个计时器。

。假设你想每10分钟开始一次任务a,它需要2秒运行一次。你的计时器启动了,10分钟后它会被唤醒并运行taskA。开始,结束,再加10分钟。但是运行你的任务需要2秒。因此,从代码运行的时间开始算起的10分钟将会有2秒的偏差。

你需要做的是预测下次你需要跑步的时间,找到现在和那时的差异,并将计时器设置为这个差异。