定时器触发 Tick 事件,延迟 15 毫秒
Posted
技术标签:
【中文标题】定时器触发 Tick 事件,延迟 15 毫秒【英文标题】:Timer firing Tick event with 15 milliseconds delay 【发布时间】:2015-07-12 00:25:05 【问题描述】:我遇到了一个奇怪的计时器问题。据我所知,计时器的间隔属性表示将触发 timer_Tick 事件的循环之间的延迟。
之前在 Visual Basic 中编程时,我遇到过精确签名(延迟 15 和 16 毫秒)的问题。我创建的任何计时器都会以 15 或 16 毫秒的延迟触发它们的滴答事件。例如,如果我将计时器的间隔设置为 1(这意味着它的滴答事件应该在 1 秒内触发 1000 次),则该事件会在 1 秒内触发 62 到 66 次(即 1000/16 到 1000/15 )。
我从 5 年前开始开发 VB 应用程序并且一直遇到这个问题(这也意味着我在使用 AMD 和 Intel 处理器的几个不同系统上遇到了这个问题),现在我在使用 C# 时又遇到了这个问题。
我设法通过基于 TickCount 方法(VB 中的 GetTickCount API 和 C# 中的 Environment.TickCount)计算每次触发滴答事件之间的时间差来解决此问题。
*TickCount 是自系统启动以来经过的毫秒数。
为了更好地理解这个问题,我创建了一个 Windows 应用程序,它计算自执行以来的秒数(如计时器)。每次触发 Tick 事件时,它都依赖于 TickCount 和普通加法。它还通过从 TickCount 的当前值中减去 TickCount 的最后一个值来计算计时器的延迟(如果计时器确实在 1 秒内被触发了 1000 次,那么每次 TickCounts 的差值将是 1,因此表示没有延迟,但如果差值大于 1,则每次触发计时器的滴答事件之间会有一些延迟)。
代码如下:
public partial class Form1 : Form
int localTime = 0, systemTime = 0, baseSystemTime = 0, lastSystemTime = 0;
public Form1()
InitializeComponent();
private void timer1_Tick(object sender, EventArgs e)
// Calculate time based on TickCount
if (baseSystemTime == 0)
baseSystemTime = Environment.TickCount;
systemTime = Environment.TickCount - baseSystemTime;
label2.Text ="System Time: " + ((systemTime / 1000) / 60).ToString() + ":" + ((systemTime / 1000) % 60).ToString();
// Calculate time based on timer1_Tick
localTime++;
label1.Text = "Application Time: " + ((localTime / 1000) / 60).ToString() + ":" + ((localTime / 1000) % 60).ToString();
// Calculate the delay
if (lastSystemTime > 0)
label3.Text = "Delay: " + (Environment.TickCount - lastSystemTime).ToString() + " ms";
lastSystemTime = Environment.TickCount;
我还在这里上传了整个解决方案:http://ramt.in/test/TimerDelay.zip
这是应用程序的屏幕截图(延迟 15 毫秒,应用程序计算 1 秒,而实际上已经过去了 17 秒!):
该解决方案只有50kb,所以请随意下载并运行它,看看你是否得到与我相同的结果。如果都一样,那么微软世界的定时器类有问题!
但更重要的是,如果有人知道可能导致此延迟的原因,请与我分享您的知识。
【问题讨论】:
timer is not working well with TimeSpan from milliseconds的可能重复 Windows 不是实时的,所以会发生这种情况。看看这个ideveloper-dotnet.blogspot.com/2013/07/… 【参考方案1】:这与实时与否无关:Windows 默认计时器分辨率为 64 滴答/秒或 15.625 毫秒。但是,系统计时器分辨率可以修改为以更高的分辨率运行,例如1 毫秒。请参阅this 回答问题“为什么 .NET 计时器的分辨率限制为 15 毫秒?”以了解如何修改系统计时器分辨率。
【讨论】:
有没有比改变定时器分辨率更好的方法?使用 System.Timers.Timer 代替 System.Windows.Forms.Timer(VS 工具箱中的默认计时器)会更准确吗? 很遗憾没有。但是,您可以查看 how to set timer resolution from C# to 1 ms? 以查看 c# 示例。但你也应该记住Why does increasing timer resolution via timeBeginPeriod impact power consumption?。【参考方案2】:这是一个系统问题,不是 c# 或 VB。要检查您的系统玩具的准确度,可以使用Stopwatch
类和两个属性
-
IsHighResolution -
The timer used by the Stopwatch class depends on the system hardware and operating system. IsHighResolution is true if the Stopwatch timer is based on a high-resolution performance counter. Otherwise, IsHighResolution is false, which indicates that the Stopwatch timer is based on the system timer.
频率
MSDN 的以下代码显示了它的工作原理
public static void DisplayTimerProperties()
// Display the timer frequency and resolution.
if (Stopwatch.IsHighResolution)
Console.WriteLine("Operations timed using the system's high-resolution performance counter.");
else
Console.WriteLine("Operations timed using the DateTime class.");
long frequency = Stopwatch.Frequency;
Console.WriteLine(" Timer frequency in ticks per second = 0",
frequency);
long nanosecPerTick = (1000L*1000L*1000L) / frequency;
Console.WriteLine(" Timer is accurate within 0 nanoseconds",
nanosecPerTick);
更新
你的代码也出错了:
// Calculate time based on timer1_Tick
localTime++;
label1.Text = "Application Time: " + ((localTime / 1000) / 60).ToString() + ":" + ((localTime / 1000) % 60).ToString();
这一行没有什么时间过去的。它只计算timer1_Tick
运行了多少次。 1 毫秒的间隔对于 Windows 窗体计时器来说太小了。你可以在这里阅读:Timer takes 10 ms more than interval
如果您需要更精确的计时器,可以查看这篇文章Microsecond and Millisecond C# Timer
【讨论】:
做了并得到了这些结果:IsHighResolution 返回 true,频率为 2338336,精度为 427 纳秒。这是什么意思? 我看了这篇文章(微秒定时器),这就是我要找的,但是,只有一个问题,那就是跨线程问题。我该如何解决?是否有等同于 SynchronizingObject 的属性? @RamtinSoltani MicroTimerElapsedEventHandler 是您可以在威胁中处理的代表 让我的问题更具体一些,我为事件处理程序分配了一个函数(使用委托),然后在该函数中我倾向于更改表单中控件对象的属性。这就是我得到编译器错误的地方,说我无法从另一个线程访问该对象。 这是一个常见错误。看这里:***.com/questions/9732709/…以上是关于定时器触发 Tick 事件,延迟 15 毫秒的主要内容,如果未能解决你的问题,请参考以下文章