【问题标题】:High-precision sleeping / waiting in .net.net中的高精度休眠/等待
【发布时间】:2016-05-30 22:12:33
【问题描述】:

背景:我在 F#/.net 中编写了一个 gameboy 模拟器。在 gameboy 中,vblank (~fps) 约为 60 Hz,并且与游戏速度相关,因此模拟器运行速度尽可能接近 60 fps 非常重要。

由于现代计算机可以以比 60 fps 快得多的速度运行我的模拟器,我需要降低模拟器的速度。我目前的方法是计算两个 VBlank 之间的时间,然后等待该 vblank 周期的剩余时间。

问题在于如何在不忙于循环 cpu 的情况下等待。由于我通常需要等待几毫秒(有时更多,有时更少),因此内置的 Thread.sleep 函数不是一个好的选择,因为除非您指定 0 等待时间,否则它将至少休眠约 15 毫秒,即方法很长(而且不准确)。我目前的方法是使用 sleep(0) ,这实际上只是一个花哨的自旋锁(其他线程可能会在其中运行,但您仍然可以最大限度地利用 cpu)。

解决这个问题的正确方法是什么?我正在考虑等待从计时器释放的信号量,但是计时器可以提供所需的时间分辨率吗?这不就是一个美妙的睡眠吗?

编辑:这被标记为 What Thread sleep method is most precise: Monitor.Wait vs System.Timer vs DispatchTimer vs Threading.Timer 的重复项,但我认为这不是精确度问题,而是为紧凑的游戏循环找到合适的解决方案。

【问题讨论】:

标签: .net windows performance emulation sleep


【解决方案1】:

正如您所指出的,默认系统计时器不够快 - 15.6 毫秒能够达到 60 FPS,但不是“每帧恒定时间”或任何接近的时间。

一种解决方案是使用繁忙循环,但是是的,对于如此长的等待时间,这是一种巨大的浪费(有趣的是,一种方法“太短了”,而另一种方法“太长了”:))。

另一个选项是使用timeBeginPeriod (https://msdn.microsoft.com/en-us/library/windows/apps/dd757624(v=vs.85).aspx) 更改系统计时器 - 您需要使用 P/Invokes 来访问此 API,但它可以让您以更高的准确度进入睡眠状态。或者更好的是,使用设置为 ~16.7ms 的 Timer。

如果您不想搞砸,只需制作一个计时器(System.Threading.Timer,而不是 windows 窗体)并将其设置为 15 毫秒。虽然这不会给你准确的 60 FPS,但它应该平均每秒大约 64 次更新,这应该足够接近以至于不容易被注意到。由于计时器回调与“睡眠”分离(没有真正的睡眠,但在等待计时器触发时您没有做 CPU 工作),它不会像 Windows 窗体那样倾向于跳过或加倍帧。请注意,这隐含涉及多线程,因此请确保正确使用同步。

【讨论】:

  • 啊,我不知道timeBeginPeriod,会调查。关于计时器,您认为连续触发计时器并释放在 vblank 函数中等待的信号量或为每个新的 vblank 创建一个新计时器会更好吗?值得一提的另一件事是,我目前正在使用 xamarin/pcl 将模拟器移植到 ios/android,我认为我可以使用 usleep 来缩短睡眠时间。
  • @monoceres 您需要使用计时器线程 - 如果 Wait 必须等待,它将再次使用系统计时器时间片,这意味着您将倾向于跳过帧,并且由于最后一个时间片你有的是计时器本身,你会或多或少地错过每次。与其使用 vblank 函数,不如让您的游戏循环从计时器一次运行一步 - 可能感觉很奇怪,但这就是基于事件的编程的工作方式:) 即使 Timer 也不是可移植的,AFAIK -例如,我似乎记得在某些 nix 系统(包括 Mac OS X IIRC)上,睡眠会最多等待时间。
  • @monoceres ...因此您很可能在不同的系统上以比预期更快的速度触发计时器回调(例如,完全没有延迟)。这是根本没有标准化的事情之一,您可能需要在每个平台上使用不同的方法:)
  • 我确实尝试过避免可变性,但在模拟器中说起来容易做起来难重做,尤其是使用代理和可能的异步工作流。说到建设者,这是我在 F# 中似乎从来没有想过的一件事,正如我想我所理解的那样,一些事情的出现当然让我完全震惊了.. :)
猜你喜欢
  • 1970-01-01
  • 2013-07-26
  • 2015-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-20
  • 2010-12-29
相关资源
最近更新 更多