如何编写适当的CPU利用率?

Tal*_*yed 4 c c# c++ language-agnostic performance

跟我说,这可能有点难以解释清楚.我试图了解如何编写仅使用所需CPU数量的程序.解释起来有点混乱,所以我只想用一个真实的例子.

我制作了一个带有无限主游戏循环的俄罗斯方块游戏.我把它限制在40 fps.但是循环仍然每秒执行数千甚至数百万次.它只是在经过足够的时间后将其限制为40 fps.

由于我有一个4核CPU,当我运行游戏时,一切都很好,游戏运行良好.但游戏过程的CPU使用率保持在25%.这是预期的,因为它是一个无限循环并持续运行.

然后我在线阅读为主循环添加1 ms的延迟.这立即将使用量减少到约1%或更低.这很好,但现在我故意每个循环等待1毫秒.它的工作原理是因为我的主循环执行时间少得多,1ms延迟不影响游戏.

但是,如果我制作更大的游戏呢?具有更长和更多处理器密集循环的游戏.如果我需要1ms时间片来顺利运行游戏,该怎么办?然后,如果我删除延迟,处理器将再次跳到25%.如果我添加延迟,游戏将会很慢并且可能会有一些延迟.

在这种情况下,理想的解决方案是什么?真实游戏/应用程序如何编码以防止出现此问题?

sli*_*lim 5

由于您在标签中列出了三种不同的语言,因此我将保留此常规,而不是提供代码示例.

一般来说,为避免烧毁CPU,永远不要在每次迭代时都有一个循环:

  • 做有用的工作
  • 基于循环计数器跳过
  • 或者调用一些阻塞调用,阻止I/O或线程wait().

sleep() 是阻塞调用的一个例子,但正如你所观察到的,在许多情况下它有点像躲避.

所以:

while(true) {
    if(some_condition) {
        foo();
    }
}
Run Code Online (Sandbox Code Playgroud)

... 不好.(我的一个朋友曾经用这样的代码把一个共享的大型机带到了膝盖上)

您需要找到对显示API的调用,该调用将阻塞直到垂直同步.device.Present()如果设备设置得当,我相信DirectX 是一个这样的调用.

在单线程游戏中,逻辑可能会:

 while(game is active)
    read user input
    calculate next frame
    blocking call to display API
Run Code Online (Sandbox Code Playgroud)

因此,CPU得到休息,每次等待垂直同步.

至少有两个线程更常规,一个处理渲染循环,另一个处理游戏状态.在这种情况下,渲染循环需要像以前一样等待垂直同步.游戏状态循环需要阻塞,直到渲染循环准备就绪.

渲染线程循环:

  while(game is active)
      notify()
      prepare_frame(game_state)
      blocking call to display API
Run Code Online (Sandbox Code Playgroud)

游戏状态线程循环:

  while(game is active)
      read user input
      update game_state
      wait(display_loop_thread)
Run Code Online (Sandbox Code Playgroud)

一定要了解线程等待/通知/加入,以便理解这一点.

此模型允许您拥有其他也会影响游戏状态的线程.例如,另一个线程可能控制AI敌人.

另一种方法是使计算事件驱动,并在vsync之后触发它们:

 while(game is active)
     calculate next frame
     blocking call to display API
     gameLogic.onFrame()
Run Code Online (Sandbox Code Playgroud)

如果onFrame()花费的时间超过一帧,那么游戏的帧速率就会受到影响.这是否重要取决于游戏; 解决方案超出了这个答案的范围 - 如果对你很重要,那么可能是时候买一本关于视频游戏架构的书.