为什么System.Timers.Timer.Interval的数据类型是double?

16

这有点像一个学术问题,因为我对Microsoft在Interval属性中使用double数据类型背后的思考感到困惑!

首先从MDSN所述,Interval是Elapsed事件之间的时间,以毫秒为单位;我会将其解释为一个离散数字,那么为什么要使用double?使用int或long更加合理吧!?

Interval是否支持像5.768585(5.768585毫秒)这样的值?特别是考虑到System.Timers.Timer并没有接近亚毫秒的精度...NET中最精确的计时器?

对我来说似乎有点傻..也许我漏掉了什么!


你试过了吗?你使用过反汇编工具之一来查看非整数值如何被处理到底层的Win32 API吗? - Richard
对我来说没有太多意义。合理的选择应该是 intTimeSpan - CodesInChaos
@Richard,你是在暗示我答案吗?我不确定为什么我应该做这样的事情?双精度浮点数的值是否是Win32 API类型约束的结果? - Dave Lawrence
我怀疑可能是这样,但我不确定(因此我不想引导你得出我已经知道的答案)。更多的问题是:你尝试过自己找到答案吗? - Richard
2个回答

13

分解显示间隔是通过调用 (int)Math.Ceiling(this.interval) 来使用的,因此即使您指定了实数,它在使用之前也会被转换为一个 int。这发生在名为 UpdateTimer 的方法中。

为什么呢?不知道,可能规范曾经要求使用 double,但后来改变了?最终结果是,double 并不是必需的,因为它最终会被转换为一个 int,根据文档,它也不能大于 Int32.MaxValue

是的,计时器可以“支持”实数,只是它没有告诉您它默默地将它们改变了。您可以使用 100.5d 初始化和运行计时器,它会将其转换为 101

而且,这一切有点蠢:浪费了 4 个字节,潜在的隐式转换、转换调用、显式转换,如果他们只使用了 int 就可以避免这些无谓的操作。


我的猜测是计时器的分辨率在理论上未来可能会提高(少于一毫秒),他们只是为了未来做好准备。也许这只是在1.1版本中出现的错误,而他们不想进行破坏性更改,所以只是把它带了过来。 - Chris Sinclair
@ChrisSinclair 可能是这样,但当你深入实现时,所有都依赖于System.Threading.Timer,后者又使用了一个未经管理的定时器(我想)。这一切都归结于使用uint。所有这些使得选择double更加奇怪,因为基类根本不使用它。 - Adam Houldsworth
@both:100纳秒分辨率的int并不能完全解决计时器的能力。请见下面我的回答。 - Arno

5
使用double的原因是为了提供足够的精度。
具体来说:系统中断时间片由ActualResolution给出,它是由NtQueryTimerResolution()返回的。NtQueryTimerResolution由本地Windows NT库NTDLL.DLL导出。系统时间增量由GetSystemTimeAdjustment()返回的TimeIncrement给出。
这两个值决定了系统计时器的行为。它们是整数值,以100纳秒为单位。然而,对于某些硬件来说,这已经不够了。在某些系统上,ActualResolution返回9766,这将对应于0.9766毫秒。但实际上,这些系统正在以1024次每秒的速度运行(通过适当设置多媒体接口进行调整)。1024次每秒的中断将导致中断周期为0.9765625毫秒。这太过详细了,它进入了100皮秒的范畴,因此无法保持在标准的ActualResolution格式中。
因此,决定将这样的时间参数放入double中。但是:这并不意味着所有可能的值都得到支持/使用。由TimeIncrement给出的粒度将持续存在,无论如何。
处理计时器时,始终建议查看涉及的参数的粒度。
所以回到你的问题:Interval是否支持像5.768585(毫秒)这样的值? 不支持,我以上面的例子所选的系统不支持。 但它可以支持5.859375(毫秒)! 其他具有不同硬件的系统可能支持其他数字。
因此,在这里引入double的想法并不是一个愚蠢的想法,实际上是有意义的。为了最终正确,再花费4个字节是一个好投资。
我在这里总结了一些关于Windows时间问题的详细信息。

虽然我不会说你所说的不准确,但就System.Timers.Timer而言,它根本不支持double,因为在Math.Ceiling调用后立即转换为int - 在这种情况下否定了使用double的意义。 - Adam Houldsworth
@AdamHouldsworth: 嗯,我并不是说所有这些实现都是正确的。只是一次性改变所有东西是不可能的。因此,前端(System.Timers.Timer)间隔属性已经得到了合理的格式,这可能会持续很长时间。但是:底层软件必须正确处理这种扩展精度才能达到更好的结果。感谢您表明这还没有正确完成。所以需要更多工作才能让事情变得正确。 - Arno
提供实际原因的逻辑可以得到加分。问题要求提供原因,而被接受的答案并没有提供。方法的实现在每次更新时都会发生变化,也许他们确实计划在未来使用类似的东西。 - ThunderGr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接