C#.NET 2 Threading.Timer - 时间漂移

时间:2011-12-08 13:51:49

标签: c# .net multithreading timer

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

我的问题:我发现在测试过程中,每天进行每日检查的时间会慢慢偏离8.30的预期开始时间。例如大约20多天,我的时间从08.30漂到08.31.35。它每天漂移4-6秒。

我的问题:有没有人知道为什么时间会像这样飘过,我怎么能让它坚持到规定的时间?

感谢

5 个答案:

答案 0 :(得分:6)

时间“漂移”,因为计时器根本就不那么精确。如果您需要尽可能密切地运行代码,您可以执行以下操作:

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实例。如果您使用任何其他类型的计时器(有几个!),请修改示例。

答案 1 :(得分:0)

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

即:

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

答案 2 :(得分:0)

在你的计时器方法处理程序中执行你正在进行的操作需要花费有限的时间,所以有意义的是它不会每隔10分钟发生一次到第二次,特别是如果你在下一次唤醒后安排下一次唤醒你的支票等。如果你已经在检查是否有时间进行回答是时候这样做,你应该让你的计时器更频繁地开火以满足你需要的分辨率,并相信你应该检查何时应该执行某些事情以确保它能够做到。您可能需要某种持久性来确保它不会执行两次(如果这很重要),以防关闭/重启并且知道它是否已经运行的状态仍然不在内存中。

答案 3 :(得分:0)

这是我的看法:

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!");
}

答案 4 :(得分:0)

定时器不准确,只是近似值。不要使用“只需添加10分钟”的逻辑。每次计时器触发时,您都需要检查时间偏差并进行调整。

例如。如果你说“在10分钟内叫醒我”,它会在10分1秒内唤醒你,那么下一个计时器需要9分59秒,而不是10分钟。

此外,您希望在逻辑结束时分配下一个计时器。

例如。假设您想每10分钟启动一次任务,并且需要2秒才能运行。你的计时器启动,10分钟后它就会启动以运行taskA。它开始,结束,现在你加10分钟。但是花了2秒钟来完成你的任务。因此,距您的代码运行10分钟将会缩短2秒。

您需要做的是预测下次需要运行并找到现在和之后的差异,并将计时器设置为该差异。