我正在用Java编写一个游戏,它在后台进行一些机器学习以生成过程,我希望它在n milliseconds
之后短暂地脱离后台训练例程,以渲染帧并更新NPC等等。
关键是n
不能被高估,因为游戏需要在所有功能强大的硬件上锁定到16ms的帧,而lgwjl中的渲染内容本身就是一种平衡行为。
问题是System.nanoTime()
在我的环境中似乎不起作用(它会导致比预期小几个数量级的超时;根据我的经验,HPC计时器非常不稳定)。System.getCurrentTimeMillis
似乎没有很好地指定舍入行为,这意味着它可能高估了近一毫秒,这是不可接受的。
有人知道是否有一个好方法可以做到这一点吗?
这样做会很痛苦。您所描述的基本上是操作系统(在Java的情况下是JVM)的上下文切换,它应该抽象为不需要直接使用。
相反,您应该有一个用于处理业务逻辑的线程,以及一个用于管理和更新显示的完全独立的线程。然后,这两个线程通过一个控制器进行通信,该控制器要么运行在自己的线程中,要么运行在与业务逻辑线程相同的线程中(具体取决于数据传输的复杂性)。这个概念被称为模型-视图-控制器模式,已经写了很多关于如何最好地实现它的文章
通过分离这些行为,您可以让业务逻辑连续运行而不需要中断,并且您的视图线程可以非常简单,基本上看起来如下:
while(true) {
long initTime = curTime();
// this will refresh the GUI and also show any new data from the controller
refresh();
sleep(curTime()-initTime);
}
当然,我想,你的问题的核心是我上面调用的这个神奇的sleep()
方法。我将更新所花费的时间量传给它,这样它就可以从所需的总睡眠时间中减去,然而,如何确保实际睡眠时间高度精确的问题更为复杂。
你说System.nanoTime()
在你的环境中是不精确的,不幸的是,这很可能会破坏你的交易。System.nanoTime()
将提供您的操作系统/处理器发布的最细粒度的运行时间数据,因此,如果此方法不能提供您所需的数据,您的机器/JVM可能无法提供您所需要的粒度。
主要的游戏/模拟开发者面临着同样的问题,并且早就通过消除精确帧更新时间的要求来解决了这个问题,因为试图以任何可靠的方式将处理时间与现实世界的时间对齐太复杂了(例如,假设操作系统暂停了你的程序几毫秒,这样处理下一帧的时间就会比允许的时间更长,你会怎么办?)。
相反,游戏和模拟等可视化的总体目标是计算模型的最新状态,并允许视图尽可能查询新信息。考虑下表:
| Time | Model | Slow View | Med. View | Fast View |
| 1 | 1 | 1 | 1 | 1 |
| 2 | | | | 1 |
| 3 | 3 | | | 3 |
| 4 | | | 3 | 3 |
| 5 | 5 | | | 5 |
| 6 | | 5 | | 5 |
| 7 | 7 | | 7 | 7 |
| 8 | | | | 7 |
| 9 | | | | 7 |
| 10 | 10 | | 10 | 10 |
| 11 | | 10 | | 10 |
| 12 | 12 | | | 12 |
| 13 | | | 12 | 12 |
| 14 | 14 | | | 14 |
| 15 | | | | 14 |
| 16 | 16 | 16 | 16 | 16 |
在这里,我们看到了一个任意的时间单位(系统上可用的最高精度)——一个尽快计算给定时间内状态的模型,以及试图显示其可用的最新状态的视图。视图运行得越快,达到模型的速度,视图在视觉上就越平滑,如果视图运行得比这快,那就不是什么问题,尽管它不会变得更平滑。但不管怎样,从用户的角度来看,模型的状态是实时更新的。
这里的关键见解是让你的模型计算给定时刻的状态,无论该值是多少,而不是试图让你的模式以任何精确的速率运行,这在共享硬件上基本上是不可能的。