【问题标题】:c# each second a tickc# 每秒一个刻度
【发布时间】:2022-01-06 14:31:29
【问题描述】:

我想编写一个程序,它需要每秒获取一个滴答事件。 该程序运行了很多小时,并且滴答声必须与系统时钟的秒数一致。 使用任何一种每秒触发一个事件的计时器都不是一个好主意。有很多不准确之处。 如果您的误差为每秒 100 毫秒,则计时器每小时比系统时钟晚 6 次。 但是,它必须与系统时钟完全一致。

从系统时钟获取事件是可以的。

有几秒钟的不准确是可以的,但不是全部。

你有什么解决这个问题的建议?

解决方案必须在c# net6上运行(我打算在Windows和Linux上运行程序)。

谢谢

【问题讨论】:

  • 你尝试了什么?
  • 解决此问题的一种方法是为计时器设置一个更短的间隔,然后使用绝对时间 (DateTime.Now) 来查看是否该增加您的秒数。
  • 在以前版本的软件中,我使用了 Winmm.dll 解决方案。这是非常准确和有效的。新版本必须能够运行 Linux。所以,Winmm.dll 不再是解决方案了。
  • 您确认每秒钟触发一次的计时器是不准确的吗?我认为不会。很容易测试。

标签: c# timer


【解决方案1】:

这会让你在时钟的每一整秒后的 0..20 毫秒内到达。

static System.Threading.Timer timer = new(CallBack, null, 0, 0);

static void CallBack(object? state)
{
  var now = DateTime.Now;
  timer.Change(1000 - now.Millisecond, 0);

  // Console.WriteLine(now + " " + now.Millisecond);
}

【讨论】:

  • 第一个快速测试看起来很有希望。我会做一个更密集的测试。
  • 永久运行6h后,这个方案只差了4秒。就是这样,非常感谢。
【解决方案2】:

如果准确性是一个问题,并且您不喜欢引发事件的计时器的准确性,那么一个简单的解决方法是使用轮询方法。

我并不是说这很有效,您希望确保为每个 tick 执行的任务在比您要启动的单元更短的时间内完成,所以在这个case 秒,但它满足与系统时钟紧密绑定的要求:

Action tickAction = () => Console.WriteLine(DateTime.Now);
int lastTick = DateTime.Now.TimeOfDay.Seconds;
while (true)
{
    var seconds = DateTime.Now.TimeOfDay.Seconds;
    if(lastTick != seconds)
    {
        lastTick = seconds;
        tickAction();
    }
}

您也可以在每个动作之后启动一个计时器,其延迟等于下一秒剩余的滴答数,但这对于 1 秒计时器来说有点矫枉过正。但是,如果时间间隔是可变的,或者执行操作所花费的时间可能超过下一个窗口,那么以基于计时器的方式执行此操作可能足够有意义。

整个事件处理循环以及后台发生的任何其他事情都会影响即使是此解决方案的准确性,拥有更多关于您希望每秒执行的操作的上下文将有助于产生更具商业可行性的解决方案.

【讨论】:

  • 这或多或少是我已经尝试过的。每秒设置一个计时器并执行以下操作:在滴答后保持实际时间,采用新时间并计算持续时间检查持续时间是否为 1 秒但这并不是很稳定,我认为必须有更好的方法。最好是从系统时钟中获取每一秒的滴答声。
  • 如果您只是渲染一个时钟,那么一个具有 20 毫秒延迟(或更短)的永久计时器会更新视觉效果,从而使事物在视觉上与实际系统时钟保持同步。每秒 50 次使用相同内容更新视觉对象并不重要,它只是一个时钟。
猜你喜欢
  • 2019-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-21
  • 2020-09-11
  • 2021-03-19
  • 1970-01-01
相关资源
最近更新 更多