我调用了 timeBeginPeriod(1),但它没有用

Posted

技术标签:

【中文标题】我调用了 timeBeginPeriod(1),但它没有用【英文标题】:I called timeBeginPeriod(1), but it didn't work 【发布时间】:2019-08-31 19:35:20 【问题描述】:

Window 对 Thread.Sleep() 的默认精度为 15.625 ms (1000 / 64),即如果您调用 Thread.Sleep(1),则经过的时间为 15 ms 或 16 ms。我想将精度提高到 1 毫秒。

有一个函数“timeBeginPeriod”可以改变精度。但我没有得到我想要的。这是我的代码:

[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
public static extern void TimeBeginPeriod(int t);

[DllImport("winmm.dll", EntryPoint = "timeEndPeriod")]
public static extern void TimeEndPeriod(int t);

TimeBeginPeriod(1);
var t1 = Environment.TickCount;
Thread.Sleep(1);
var t2 = Environment.TickCount;
Console.WriteLn(t2 - t1);
TimeEndPeriod(1);

我预期的是 1 或 2,但实际上我得到了 15 或 16。

有没有我遗漏的代码?

【问题讨论】:

您是否尝试了相同的没有 Thread.Sleep?我很好奇 t1t2 之间有什么区别 来自Thread.Sleep 文档:实际超时可能不完全是指定的超时,因为指定的超时将被调整为与时钟滴答相吻合 你永远不会得到预期的 1 或 2 毫秒,因为执行 Thread.Sleep 的时间最少为 4 或 5 毫秒 我不知道Environment.TickCount 多久更新一次,是否确实受到设置计时器分辨率的影响,但调用TimeBeginPeriod(1) 确实将Sleep() 的分辨率更改为(大约)对我来说是 1 毫秒。 根据我的个人经验,Thread.Sleep 即使设置TimeBeginPeriod 也是完全不可靠的。最好使用Multimedia Timers。 【参考方案1】:

根据各个论坛的讨论,我怀疑此功能在 Windows 10 上被破坏了一段时间,但它似乎已在我运行 Windows 10 版本 2004 的机器上修复。没有调用 timeBeginPeriod,睡眠计时器分辨率约为 15 毫秒。调用 timeBeginPeriod(1) 后,睡眠定时器分辨率下降到 1..2 毫秒

其他人能否在最新的 Windows 系统上确认这一点?

附录 1:我刚刚找到 https://***.com/a/48011619/295690,这表明即使该功能实际上可能已修复,但仍有充分的理由避免它。

附录 2:来自https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/ 的更多见解让我认为这不仅仅是操作系统版本的问题。我可以想象某些省电模式或硬件配置会阻止程序提高系统范围的滴答频率。

【讨论】:

【参考方案2】:

我有一些关于这个问题的更新。

Environment.TickCount 的准确率约为 16ms。这不是一个高精度的方法。实际上,通过使用 DateTime,即使在 Windows 10 版本 1903 上不使用 TimeBeginPeriod/TimeEndPeriod,我们也可以获得更准确的经过时间。

long t1 = Environment.TickCount;
DateTime dt1 = DateTime.Now;
Thread.Sleep(1);
DateTime dt2 = DateTime.Now;
long t2 = Environment.TickCount;
Console.WriteLine("DateTime Method: " + (dt2-dt1).TotalMilliseconds);
Console.WriteLine("TickCount Method: " + (t2 - t1));

DateTime Method: 2.0074
TickCount Method: 0

【讨论】:

以上是关于我调用了 timeBeginPeriod(1),但它没有用的主要内容,如果未能解决你的问题,请参考以下文章

具有毫秒精度的 Linux/OSX 时钟分辨率?

装饰器不支持函数调用,但调用了“AngularFireModule”

未调用 UIcollectionView 的 didDeselectItemAt 但调用了 didSelectItemAt?

删除调用析构函数但不删除对象?

Oracle AWR - 高 SQL 解析调用但 0 次执行

调用了 Deinit 但对象仍在内存中