System.Threading回调似乎不准确

时间:2015-05-25 16:25:37

标签: c# timer

我的申请会收到客户的指示。

在每条指令上,我想从接收的时间戳+ 10秒执行代码。

为了测试我的代码的准确性,我模拟了这个简单的控制台测试:

    static DateTime d1 = DateTime.Now;
    static Timer _timer = null;
    static void Main(string[] args)
    {
        _timer = new Timer(Callback, null,200, Timeout.Infinite);
       d1 = DateTime.Now;
       Console.ReadLine();
    }

    private static void Callback(Object state)
    {
        TimeSpan s = DateTime.Now - d1;
        Console.WriteLine("Done, took {0} secs.", s.Milliseconds);
        _timer.Change(200, Timeout.Infinite);
    }

在运行它时我曾希望显示:

Done, took 200 milsecs.
Done, took 200 milsecs.
Done, took 200 milsecs.
Done, took 200 milsecs.
Done, took 200 milsecs.
Done, took 200 milsecs.

但事实并非如此。

我得到'milsecs'的随机值。

NB 我的实际代码并不总是使用200毫秒。

屏幕截图示例:

enter image description here

2 个答案:

答案 0 :(得分:3)

首先,您使用TimeSpan.Milliseconds属性,即int并且只返回时间跨度的毫秒部分。为确保您获得全职,请使用TotalMilliseconds

其次,您没有在每个循环中重置d1,因此您将看到时间,而不是每次迭代的时间。要解决此问题,请务必在回调结束时设置d1 = DateTime.Now,以便下一个循环使用正确的时间。

最后,由于线程,方法调用甚至是您正在进行的减法操作的开销,您可能会看到一定的差异,而不是完美的200ms间隔。此外,根据this article from Eric Lippert

DateTime并不总是具有最高的准确性
  

如果你想问的问题是一些操作有多长   花了,你想要一个高精度,高精度的答案,然后使用   StopWatch班。

因此:

static Stopwatch _watch = Stopwatch.StartNew();
static Timer _timer = null;
static void Main(string[] args)
{
    _timer = new Timer(Callback, null,200, Timeout.Infinite);
   Console.ReadLine();
}

private static void Callback(Object state)
{
    TimeSpan s = _watch.Elapsed;
    _watch.Restart();
    Console.WriteLine("Done, took {0} secs.", s.TotalMilliseconds);
    _timer.Change(200, Timeout.Infinite);
}

答案 1 :(得分:1)

s.Milliseconds可以说是小数点后的毫秒数。您需要TotalMilliseconds。这些属性非常有名。它们是许多SO问题的原因。

内置定时器应该有大约15ms的分辨率(或者它的一小部分)并且可能有一些偏差(我不知道)。