我的多线程游戏一直处于 100% CPU。如何管理线程活动以减少 CPU 负载?

Posted

技术标签:

【中文标题】我的多线程游戏一直处于 100% CPU。如何管理线程活动以减少 CPU 负载?【英文标题】:My multithreaded game is at 100% CPU all the time. How can I manage thread activity to reduce the CPU load? 【发布时间】:2014-01-31 22:44:50 【问题描述】:

我有一个 DirectX 游戏,它在双核系统上生成 2 个增强线程:1 个用于游戏/渲染(通常在四核 CPU 上拆分为它们自己的线程),另外 1 个线程在程序上生成游戏世界.我相信我的音频中间件也会产生自己的线程来播放 SFX 和音乐。

游戏始终在 CPU 上以 100% 的速度运行,这反过来又会导致音频系统出现一些杂音。我希望我可以通过更好地管理该生成线程的活动来减少 CPU 负载。虽然有时我需要它全速运行,但也有其他时候(当玩家移动不多时)它只是在不断更新而没有真正做很多事情。

是否可以/建议手动管理线程的活跃程度?如果是这样,我可以使用什么策略来做到这一点?我一直看到人们说不推荐 sleep() 函数,但我真的不知道还能做什么。

或者,我是否通过尝试从线程管理中挤出循环来找出错误的树,传统的分析/优化会更好地为我服务吗?

【问题讨论】:

先问自己一个更简单的问题:对于一个简单的单线程程序以 100% CPU 负载运行意味着什么?如何让程序运行? 最初执行传统的分析/优化总是会为您提供更好的服务。 "当它只是不断更新而没有真正做很多事情时。"你的意思是程序生成只是不断地重新计算相同的结果吗?如果是这样,那么您要做的是让程序生成代码等到它需要生成新的东西。 @KerrekSB - 我 100% 听到你的声音,我承认这个话题经过深思熟虑和沟通,但你读过这个问题吗?我有一个线程有时有点“旋转”而没有做太多,我的问题是是否有任何实用程序可以关闭该线程或取消它的优先级以让其他线程有机会完成更多工作。也就是说,我确实理解你的意思。 @bames53 是的,差不多。但是,如何最好地让它等待呢?那个时候使用 sleep() 是正确的吗?我不知道这是否会在更大的范围内帮助我,但我只是想了解这种事情的最佳实践。 【参考方案1】:

达到 100% 的处理器利用率意味着您没有游戏时钟。您可能正在以机器允许的速度渲染帧。如果您使用多个线程,仍然很难准确地获得 100%,这表明您也没有同步线程。

这可能需要进行相当大的重写。速度应该由主渲染循环设置,该循环将后台缓冲区复制到视频适配器。它设置您的目标 FPS,即每秒帧数。经常使用显示器的垂直消隐间隔,它通过确保显示器在正确的时间得到更新来解决撕裂问题。这会自动使渲染循环与显示器刷新率同步。在液晶显示器上通常每秒 60 次。计时器是另一种选择。这可以防止主线程烧毁 100% 核心,假设它可以跟上 FPS。

您现在有一个稳定的游戏时钟滴答声,需要发生的事情和需要完成的工作以更新游戏状态的离散时刻。就像检查玩家输入一样。在渲染循环中,检查鼠标/键盘/控制器输入并使用您获得的任何东西来更新游戏世界对象。

进而决定工作线程需要做什么。他们将有一次通过渲染循环的持续时间来完成他们需要做的工作。您使用同步对象来唤醒它们。还有一个,每个,让他们发出信号,表明他们已经完成了当前的游戏循环。这阻止了他们燃烧核心,他们应该不断地等待信号开始处理下一帧。请注意,有一个平衡要求。如果工作线程需要更多来完成工作,则渲染循环将落后并错过视频适配器帧更新。您的视频开始卡顿。这通常是不可能完全消除的,请确保它不会影响绝对游戏时钟。

音频应该是更容易解决的问题,您只需要让声卡缓冲区充满足够的数据,以保存几帧的声音。

落后于目标 FPS 很容易确定。您会通过降低目标 FPS 来自动补偿这一点。所以程序在慢速机器上仍然可以接受,只是不那么流畅。最终效果是您将停止在所有线程上燃烧 100% 核心。

【讨论】:

【参考方案2】:

我对您的系统一无所知,所以这个答案可能有问题。我假设存在某种可以跟踪其大小的音频输出缓冲区。当缓冲区的大小太小以至于存在音频可能停止的危险时,您应该做一些事情来重新填充缓冲区。

“某事”可能就像临时将音频线程的优先级设置为更高的值一样简单。想想为什么不从一开始就把它设置得更高呢?这将解决所有问题,对吗?更好的是,只需降低世界生成器线程的优先级即可。

【讨论】:

感谢您的回答 - 是的,这可能是一种更聪明的方法。不幸的是,我无法访问音频缓冲区/线程,所以也许正常的优化/重新评估我的中间件可能是最好的方法。关于线程优先级 - 这是依赖于 API 还是依赖于平台?我发现的第一件事是 Windows 上的 SetThreadPriority() 函数。我在正确的轨道上吗? @Raptormeat 我看不出 API 和平台之间的区别。 Windows SDK 其实更早以前被称为 Platform SDK。但是,是的,SetThreadPriority 就是函数。不过,不太确定您为什么接受这个答案,因为您似乎想要更多的想法。已接受答案的问题通常没有更多答案。 很抱歉造成混乱,当我说 API 时,我正在考虑我用来创建线程的 Boost 线程库。无论哪种方式,这都是我可以自己解决的问题。至于你的另一点——你是对的,所以我现在不接受这个答案。我想我只是对获得更好的答案感到悲观!【参考方案3】:

多年前,当我为游戏玩家开发语音通讯应用时,我们经常遇到这个问题。许多游戏被编写为使用每一盎司的 CPU。因此,一些游戏玩家会使我们的应用程序(在后台运行)无法正常运行 - 导致音频丢失和网络连接丢失。其中许多游戏还会调用带有 REALTIME 标志的 SetThreadPriority 和 SetPriorityClass,以基本上消耗所有 CPU 量,而忽略系统上运行的其他任何东西。

我们要求与我们合作的游戏开发者的典型解决方法是在他们的主游戏循环的每一帧之间插入一个“Sleep(0)”调用,这样我们的线程就不会停滞不前。我想我们后来在软件更新中添加了一个开关,以使我们的进程以更高的优先级模式运行。从那时起,Windows 在多任务处理和线程优先级方面在这些问题上做得更好。

【讨论】:

以上是关于我的多线程游戏一直处于 100% CPU。如何管理线程活动以减少 CPU 负载?的主要内容,如果未能解决你的问题,请参考以下文章

如何排查java进程cpu100%的问题

jstack的使用方法

cpu使用率100%怎么解决?(cpu使用率100%的原因及解决办法)

CPU占用100%

CPU 百分比和繁重的多线程

Akka IO 应用消耗 100% cpu