【问题标题】:Timer once a minute on the minute计时器每分钟一次
【发布时间】:2016-05-07 19:44:09
【问题描述】:

我无法让计时器在 1:00、1:01、1:02 等每分钟触发一次。相反,当计时器执行时,每次迭代都会漂移几秒钟

   internal void StartTimer()
    {
        DateTime nowEastern = CalendarEntity.Calendar.GetEasternTime();

        int secondsInterval = 5;

        double additionalSeconds = secondsInterval - nowEastern.TimeOfDay.TotalSeconds % secondsInterval;
        if (additionalSeconds == 0)
        {
            additionalSeconds = 1;
        }
        var nearestOnOneMinutes = new DateTime(
            nowEastern.Year,
            nowEastern.Month,
            nowEastern.Day,
            nowEastern.Hour,
            nowEastern.Minute,
            nowEastern.Second
        ).AddSeconds(additionalSeconds);

        TimeSpan timeToStart = nearestOnOneMinutes.Subtract(nowEastern);
        TimeSpan tolerance = TimeSpan.FromSeconds(1);
        if (timeToStart < tolerance)
        {
            timeToStart = TimeSpan.Zero;
        }

        timer_onem = new System.Threading.Timer(OnTimedEvent, null,
                                    (int)timeToStart.TotalMilliseconds, Timeout.Infinite);
    }

    private static void OnTimedEvent(object o)
    {
        var minute = DateTime.Now.Minute;
        var second = DateTime.Now.Second;
        if (minute != lastMinute && second % 60 < 2)
        {
            lastMinute = minute;
            CodeToExecute();
        }
    }

    static void CodeToExecute()
    {
        double tms = 60000;

        // code here
        int wait = 60 - System.DateTime.Now.Second;

        timer_onem.Change(Convert.ToInt64(tms) - wait, Timeout.Infinite);
    }

编辑 1

我更改了间隔,使其每秒触发一次,然后检查分钟是否已更改。还是飘了

    timer_onem = new System.Threading.Timer(OnTimedEvent, null,
                                    (int)timeToStart.TotalMilliseconds, 1000);

    private static void OnTimedEvent(object o)
    {
        var minute = DateTime.Now.Minute;

        if (minute != lastMinute)
        {
            lastMinute = minute;
            CodeToExecute();
        }
    }

    private static void CodeToExecute()
    {
        if (bGenerate)
        {
            double tms = 1000;
            // code
            timer_onem.Change(Convert.ToInt64(tms), 1000);
        }
    }

【问题讨论】:

  • 您执行的代码是否会产生大量工作负载?如果是这样,您可能应该将其移至后台工作人员..
  • 不完全是被动代码。

标签: c# multithreading timer


【解决方案1】:

Timer保证不会比Interval

所以你需要调用它,每隔一秒说一次并检查整分钟。

为了获得更高的精度,您必须每 1/2 秒或更长时间检查一次。

这是信息论的一条基本规则,即要以给定的分辨率(在您的情况下为 1 秒)进行测量,您需要以高于该分辨率两倍的分辨率进行采样。因此,要测量 20kHz,您需要一个优于 2x20kHz 的采样率,例如 44.1kHz。 (认得数字吗?)

如果您不想为了获得一个精确的时间点而经常这么称呼它,您可以在每个 @987654323 上编写一些更复杂的代码@ 将 Timer.Interval 重置为剩余时间的不到一半,直到下一个完整分钟,直到它低于 500 毫秒..

不过,在设置预期时间方面,您的代码中发生了相当复杂的事情;确保它们不是真正的问题。应该由于计时器的精度不足而导致越来越大漂移,除非您“收集”错误..

【讨论】:

  • 参见编辑 1。似乎无助于增加定时事件的频率。
  • 你是说为了让我在整数分钟边界上执行一些操作,每秒漂移一次 +/-1(或 60000 毫秒),我必须每隔一次触发一次计时器500 毫秒?这似乎很荒谬。所以 1:01:01, 1:02:02, 1:03:02, 1:04:01 没问题,但我得到 1:01:02, 1:02:04, 1:03:06 等。以秒为单位单调递增。
  • 嗯,这是信息论的一个基本规则,它说要以给定的分辨率进行测量,您需要以两倍于该分辨率的分辨率进行采样。因此,要测量 20kHz,您需要优于 2x20kHz,例如 44kHz。 (认识数字吗?)如果只需要测量一个时间点当然是浪费;有关优化但仍然简单的算法,请参阅我的最后一段。
  • - 不确定是否可能是代码中的其他内容可能是罪魁祸首。事实上,漂移的增长必须有不同的原因。我建议您注销预期的时间,看看它们是否正常..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-30
  • 2011-06-22
  • 1970-01-01
  • 2019-11-04
相关资源
最近更新 更多