System.Threading回调好像不太准确
System.Threading callback does not seem that accurate
我的应用程序收到来自客户的指令。
在每条指令上,我想从收到的时间戳开始执行代码 + 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' 的随机值。
注意
我的实际代码不会总是使用 200 毫秒。
示例截图:
s.Milliseconds
可以说是小数点后的毫秒数。你需要TotalMilliseconds
。这些属性的名字很可怕。它们是许多 SO 问题的原因。
内置定时器应该有大约 15 毫秒的分辨率(或它的一小部分)并且可能有一些偏差(我不知道)。
首先,您使用的是 TimeSpan.Milliseconds
属性,这是一个 int
且仅 returns 毫秒 部分 的时间跨度。为确保您获得全职,请使用 TotalMilliseconds
其次,您没有在每个循环中重置 d1
,因此您会看到 总 时间,而不是每次迭代的时间。要解决此问题,请确保在回调结束时设置 d1 = DateTime.Now
,以便下一个循环使用正确的时间。
最后,由于线程、方法调用甚至您正在执行的减法操作的开销,您可能会看到一定的差异而不是完美的 200 毫秒间隔。此外,DateTime
并不总是最准确的 - 根据 this article from Eric Lippert:
If the question you want to ask is about how long some operation
took, and you want a high-precision, high-accuracy answer, then use
the StopWatch class.
因此:
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);
}
我的应用程序收到来自客户的指令。
在每条指令上,我想从收到的时间戳开始执行代码 + 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' 的随机值。
注意 我的实际代码不会总是使用 200 毫秒。
示例截图:
s.Milliseconds
可以说是小数点后的毫秒数。你需要TotalMilliseconds
。这些属性的名字很可怕。它们是许多 SO 问题的原因。
内置定时器应该有大约 15 毫秒的分辨率(或它的一小部分)并且可能有一些偏差(我不知道)。
首先,您使用的是 TimeSpan.Milliseconds
属性,这是一个 int
且仅 returns 毫秒 部分 的时间跨度。为确保您获得全职,请使用 TotalMilliseconds
其次,您没有在每个循环中重置 d1
,因此您会看到 总 时间,而不是每次迭代的时间。要解决此问题,请确保在回调结束时设置 d1 = DateTime.Now
,以便下一个循环使用正确的时间。
最后,由于线程、方法调用甚至您正在执行的减法操作的开销,您可能会看到一定的差异而不是完美的 200 毫秒间隔。此外,DateTime
并不总是最准确的 - 根据 this article from Eric Lippert:
If the question you want to ask is about how long some operation took, and you want a high-precision, high-accuracy answer, then use the StopWatch class.
因此:
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);
}