定时器触发Tick事件,延迟15毫秒

时间:2015-05-02 06:36:16

标签: c# timer timedelay gettickcount

我对计时器有一个奇怪的问题。只要我知道,定时器的interval属性指示将触发timer_Tick事件的循环之间的延迟。

在使用Visual Basic进行编程之前,我遇到了具有确切签名(15和16毫秒延迟)的问题。我创建的任何计时器都会以15或16毫秒的延迟触发其tick事件。例如,如果我将我的计时器的间隔设置为1(这意味着它的tick事件应该在1秒内被触发1000次),那么事件将在1秒内被触发62到66次(即1000/16)到1000/15)。

我从5年前开始开发VB应用程序并且一直遇到这个问题(这也意味着我在AMD和Intel处理器的几个不同系统上遇到了这个问题),现在我已经有了它再次使用C#。

我设法通过计算每次基于TickCount方法(VB中的GetTickCount API和C#中的Environment.TickCount)触发tick事件之间的时间差来解决此问题并解决此问题。

* 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秒!):

Screen Shot

解决方案只有50kb,所以请随意下载并运行它,看看你是否得到与我相同的结果。如果它是相同的,那么微软世界中的计时器类就出现了问题!

但更重要的是,如果有人知道可能导致此延迟的原因,请与我分享您的知识。

2 个答案:

答案 0 :(得分:2)

这与实时无关:Windows默认定时器分辨率为64 ticks / s或15.625 ms。然而,可以修改系统定时器分辨率以在更高分辨率下操作,例如, 1毫秒请参阅this aswer问题" 为什么.NET计时器的分辨率限制在15毫秒?"了解如何修改系统计时器分辨率。

答案 1 :(得分:1)

这是一个系统问题,而不是c#或VB。要检查系统玩具可以使用Stopwatch类和两个属性

的准确程度
  1. 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.
  2. 频率
  3. 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运行的次数。对于Windows窗体计时器,1毫秒间隔太小。你可以在这里阅读:Timer takes 10 ms more than interval

    如果您需要更精确的计时器,可以查看本文Microsecond and Millisecond C# Timer