为什么 .NET 计时器的分辨率限制为 15 毫秒? [英] Why are .NET timers limited to 15 ms resolution?

查看:32
本文介绍了为什么 .NET 计时器的分辨率限制为 15 毫秒?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请注意,我问的是使用 System.Threading.Timer 之类的东西,它会比每 15 毫秒更频繁地调用一次回调函数.我不是在问如何使用诸如 System.Diagnostics.Stopwatch 甚至 QueryPerformanceCounter 之类的东西来准确地对一段代码计时.

Note that I'm asking about something that will call a callback function more often than once every 15 ms using something like System.Threading.Timer. I'm not asking about how to accurately time a piece of code using something like System.Diagnostics.Stopwatch or even QueryPerformanceCounter.

此外,我已阅读相关问题:

Also, I've read the related questions:

准确的 Windows 计时器?System.Timers.Timer() 被限制为 15 毫秒

.NET 中的高分辨率计时器

这两个都不能为我的问题提供有用的答案.

Neither of which supplies a useful answer to my question.

此外,推荐的 MSDN 文章,实现持续更新的高分辨率Windows 的时间提供程序,是关于计时,而不是提供连续的滴答声.

In addition, the recommended MSDN article, Implement a Continuously Updating, High-Resolution Time Provider for Windows, is about timing things rather than providing a continuous stream of ticks.

话虽如此...

有很多关于 .NET 计时器对象的错误信息.例如,System.Timers.Timer 被称为为服务器应用程序优化的高性能计时器".而 System.Threading.Timer 在某种程度上被认为是二等公民.传统观点认为 System.Threading.Timer 是 Windows Timer Queue TimersSystem.Timers.Timer 完全是另一回事.

There's a whole lot of bad information out there about the .NET timer objects. For example, System.Timers.Timer is billed as "a high performance timer optimized for server applications." And System.Threading.Timer is somehow considered a second class citizen. The conventional wisdom is that System.Threading.Timer is a wrapper around Windows Timer Queue Timers and that System.Timers.Timer is something else entirely.

实际情况大不相同.System.Timers.Timer 只是一个围绕 System.Threading.Timer 的薄组件包装器(只需使用 Reflector 或 ILDASM 来查看 System.Timers.Timercode> 并且您将看到对 System.Threading.Timer 的引用,并且有一些代码将提供自动线程同步,因此您不必这样做.

The reality is much different. System.Timers.Timer is just a thin component wrapper around System.Threading.Timer (just use Reflector or ILDASM to peek inside System.Timers.Timer and you'll see the reference to System.Threading.Timer), and has some code that will provide automatic thread synchronization so you don't have to do it.

System.Threading.Timer,事实证明不是 Timer Queue Timer 的包装器.至少不是在 2.0 运行时中,它从 .NET 2.0 到 .NET 3.5 使用.几分钟的共享源 CLI 显示运行时实现了自己的计时器队列,类似于计时器队列计时器,但从未实际调用 Win32 函数.

System.Threading.Timer, as it turns out is not a wrapper for the Timer Queue Timers. At least not in the 2.0 runtime, which was used from .NET 2.0 through .NET 3.5. A few minutes with the Shared Source CLI shows that the runtime implements its own timer queue that is similar to the Timer Queue Timers, but never actually calls the Win32 functions.

.NET 4.0 运行时似乎也实现了自己的计时器队列.我的测试程序(见下文)在 .NET 4.0 下提供了与在 .NET 3.5 下类似的结果.我已经为 Timer Queue Timers 创建了自己的托管包装器,并证明我可以获得 1 毫秒的分辨率(具有相当好的准确性),所以我认为我不太可能读错 CLI 源代码.

It appears that the .NET 4.0 runtime also implements its own timer queue. My test program (see below) provides similar results under .NET 4.0 as it does under .NET 3.5. I've created my own managed wrapper for the Timer Queue Timers and proved that I can get 1 ms resolution (with quite good accuracy), so I consider it unlikely that I'm reading the CLI source wrong.

我有两个问题:

首先,是什么导致运行时对定时器队列的实现如此缓慢?我无法获得超过 15 毫秒的分辨率,精度似乎在 -1 到 +30 毫秒的范围内.也就是说,如果我要求 24 毫秒,我会得到间隔 23 到 54 毫秒的刻度.我想我可以花更多的时间使用 CLI 源来找到答案,但我想这里有人可能知道.

First, what causes the runtime's implementation of the timer queue to be so slow? I can't get better than 15 ms resolution, and accuracy seems to be in the range of -1 to +30 ms. That is, if I ask for 24 ms, I'll get ticks anywhere from 23 to 54 ms apart. I suppose I could spend some more time with the CLI source to track down the answer, but thought somebody here might know.

第二,我意识到这更难回答,为什么不使用 Timer Queue Timers?我意识到 .NET 1.x 必须在没有这些 API 的 Win9x 上运行,但它们自 Windows 2000 以来就存在,如果我没记错的话,这是 .NET 2.0 的最低要求.是因为 CLI 必须在非 Windows 机器上运行吗?

Second, and I realize that this is harder to answer, why not use the Timer Queue Timers? I realize that .NET 1.x had to run on Win9x, which didn't have those APIs, but they've existed since Windows 2000, which if I remember correctly was the minimum requirement for .NET 2.0. Is it because the CLI had to run on non-Windows boxes?

我的计时器测试程序:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace TimerTest
{
    class Program
    {
        const int TickFrequency = 5;
        const int TestDuration = 15000;   // 15 seconds

        static void Main(string[] args)
        {
            // Create a list to hold the tick times
            // The list is pre-allocated to prevent list resizing
            // from slowing down the test.
            List<double> tickTimes = new List<double>(2 * TestDuration / TickFrequency);

            // Start a stopwatch so we can keep track of how long this takes.
            Stopwatch Elapsed = Stopwatch.StartNew();

            // Create a timer that saves the elapsed time at each tick
            Timer ticker = new Timer((s) =>
                {
                    tickTimes.Add(Elapsed.ElapsedMilliseconds);
                }, null, 0, TickFrequency);

            // Wait for the test to complete
            Thread.Sleep(TestDuration);

            // Destroy the timer and stop the stopwatch
            ticker.Dispose();
            Elapsed.Stop();

            // Now let's analyze the results
            Console.WriteLine("{0:N0} ticks in {1:N0} milliseconds", tickTimes.Count, Elapsed.ElapsedMilliseconds);
            Console.WriteLine("Average tick frequency = {0:N2} ms", (double)Elapsed.ElapsedMilliseconds / tickTimes.Count);

            // Compute min and max deviation from requested frequency
            double minDiff = double.MaxValue;
            double maxDiff = double.MinValue;
            for (int i = 1; i < tickTimes.Count; ++i)
            {
                double diff = (tickTimes[i] - tickTimes[i - 1]) - TickFrequency;
                minDiff = Math.Min(diff, minDiff);
                maxDiff = Math.Max(diff, maxDiff);
            }

            Console.WriteLine("min diff = {0:N4} ms", minDiff);
            Console.WriteLine("max diff = {0:N4} ms", maxDiff);

            Console.WriteLine("Test complete.  Press Enter.");
            Console.ReadLine();
        }
    }
}

推荐答案

也许这里链接的文档解释了一点.它有点干,所以我只快速浏览了它:)

Perhaps the document linked here explains it a bit. It's kinda dry so I only browsed it quickly :)

引用介绍:

系统定时器分辨率决定Windows 执行两次的频率主要动作:

The system timer resolution determines how frequently Windows performs two main actions:

  • 更新计时器刻度如果一个完整的刻度已经过去,则计数.
  • 检查是否有预定的定时器对象已过期.

计时器滴答是经过的概念Windows 用于跟踪一天中的时间和线程量子时间.默认情况下,时钟中断和计时器滴答是相同的,但 Windows或应用程序可以更改时钟中断期.

A timer tick is a notion of elapsed time that Windows uses to track the time of day and thread quantum times. By default, the clock interrupt and timer tick are the same, but Windows or an application can change the clock interrupt period.

默认定时器Windows 7 上的分辨率为 15.6毫秒 (ms).一些应用将其减少到 1 毫秒,从而减少移动系统上的电池运行时间高达 25%.

The default timer resolution on Windows 7 is 15.6 milliseconds (ms). Some applications reduce this to 1 ms, which reduces the battery run time on mobile systems by as much as 25 percent.

原文来自:定时器、定时器分辨率和高效代码的开发 (docx).

这篇关于为什么 .NET 计时器的分辨率限制为 15 毫秒?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆