为什么线程在《奇点灰烬》* 中至关重要

创建游戏时,您需要不断在特性和性能中作出权衡。 在游戏中添加图形效果和特性时,GPU 是最突出的瓶颈,但是游戏同时也会受到 CPU 的限制。

除了来自游戏逻辑的普通 CPU 负载以外,物理和人工智能 (AI) 计算以及赋予游戏浸入式体验的图形效果也是 CPU 密集型任务,在游戏开发的过程中,GPU 和 CPU 通常交替产生瓶颈。

现代微处理器拥有强大的单核性能,但如果能够充分利用多个 CPU 内核,游戏将能够实现更好的整体性能。 为了充分利用全部的 CPU 计算功能,应用在使用多线程时运行速度最快,此时它们可以确保在所有 CPU 内核上同时运行代码。

视频地址:https://dn-moderncode.qbox.me/game/why-threading-matters-for-ashes-of-the-singularity.mp4

最近,Oxide Games 和 Stardock Entertainment 公司开发了一款实时战略 (RTS) 游戏《奇点灰烬》*,本视频展示的便是这款游戏。 您可以看到在搭载了更多 CPU 内核的系统上,这个游戏如何提供更卓越的游戏体验和性能。 

《奇点灰烬》 
图 1: 《奇点灰烬》* 展示了在搭载了更多 CPU 内核的系统上,高度线程化游戏如何获得更高的帧速率。

Oxide 创建了新的引擎并采用了 Direct3D* 12,如此一来《奇点灰烬》便能利用处理器的所有内核。 该游戏在常见的游戏系统上运行良好,在搭载了更多内核的系统上表现更佳。 您可以在游戏中采用相同的技术,以实现最佳 CPU 性能。

Direct3D* 12 消除了瓶颈并提升了性能。

为了在《奇点灰烬》中获得最快的帧速率,Oxide 团队使用了 Direct3D* 12 版本。 Direct3D 的早期版本运行良好,但是存在几个瓶颈, 在第 12 版中,API 进行了多项变更,消除了影响游戏速度的瓶颈。这些变更包括:多个对象被简化为管线状态对象,更小的硬件抽象层最大限度地降低了 API 开销,从图形驱动程序中消除了资源障碍。

Direct3D 11 能从多个线程中创建命令。 但是,由于旧版 Direct3D 需要大量的串行化,游戏从多线程中获得的加速不多。 通过调整 API,Direct3D 12 彻底消除了这一底层限制。 现在游戏无需使用串行化,便可以使用多个线程填写命令列表,从而显著改善整体线程性能。

通过充分利用这些 API 变更,《奇点灰烬》在 Direct3D 12 上能够实现运行效果。

Nitrous* 引擎使游戏成为可能

Oxide 想要创建一个比以往游戏更复杂的实时战略游戏,支持更大型的军队,拥有更多的单位和更广阔的地图。 为了创建下一代实时战略游戏,开发团队一致认为需要一个新的游戏引擎,现有的游戏引擎无法支持他们期望的单位数量和地图规模。 为了成功开发出《奇点灰烬》,他们从头开始建造 Nitrous 引擎。

任何新的引擎必须首先提供高性能的渲染, 为了达到这个目标,他们对 Nitrous 引擎进行了充分调试,使其支持最新版图形 API、多个 GPU 和异步计算。

游戏为每位玩家提供了多个单位的支持,还提供了大型地图。 在广阔的地形内模拟众多游戏内对象的物理结构生成了庞大的 CPU 负载。 更为重要的是,由于需要模拟每个单位的行为,人工智能工作负载也非常庞大。 游戏支持的大量单位还引发了突发特性。 随着单位数量的增加,玩家直接管理单位的难度不断加大。 Oxide 打造了实现人工智能的分层方法,使军队合理地协作,以利用每个单位的相对优势,同时关注它们的相对劣势。

为了实现这种拓展,Nitrous 将工作分解为更小的任务,实行了引擎的线程化。 任务系统具有较高的灵活性,小型任务可以分散于尽可能多的 CPU 内核中。 由于多数英特尔? 处理器包含英特尔? 超线程 (HT) 技术,Oxide 认真调试了面向速度的任务调度器,调度器在任务之间寻找局部性。 共享已缓存数据的任务在相同物理 CPU 内核中的不同逻辑内核上进行调度,这一方法带来了最佳性能和任务吞吐率。

不论采用何种方法,提升游戏复杂性的过程中总会遇到瓶颈。 开发游戏时,需要考虑预期的相对 CPU 和 GPU 负载。 了解当 GPU 和 CPU 分别成为瓶颈时,游戏将怎样运行。

英特尔? 酷睿? 处理器为游戏添彩

英特尔? 酷睿? 处理器能够让您的游戏如《奇点灰烬》般闪耀。 在设计和优化游戏的过程中,您应瞄准中端处理器,并提供扩展到最高端处理的能力。

借助上述技术,《奇点灰烬》在一流的英特尔? 酷睿? i7-6950X 处理器至尊版上运行良好,这款处理器有 10 个物理 CPU 内核和一个大容量高速缓存,能实现最佳的整体性能。 将工作分解为任务后,借助强大的 GPU,游戏的帧速率随着 CPU 内核数量的增加而提高。 在 CPU 内核数量不同的相同系统上,帧速率稳定增长至最高 10 个物理内核。

该游戏还包括大型地图。 由于玩家和单位数量非常庞大,装备齐全的一组玩家将造成巨大的人工智能负担。 经过认真的调试,《奇点灰烬》借助任务调度器,自动将工作自动分配至全部内核中,只有在 CPU 内核(六个及以上)数量较多的系统中显示地图。 这是一个不错的方法,您也可以效仿:如果您想选择性地启用特性,可以利用 GetsystemInfo() 等函数检测系统的内核数量。

可扩展效果使游戏更胜一筹

尽管游戏主要关注如何在内核数量较多的系统上提升帧速率,但是仍可以利用一小部分 CPU 空间为玩家带来惊喜。 随着内核数量的增多,《奇点灰烬》将在某些单位内自动启用高级粒子效果,还会启用临时运动模糊。 

时间: 2024-10-07 06:39:29

为什么线程在《奇点灰烬》* 中至关重要的相关文章

14-08-07 关于程序、进程、线程,以及python中实现多线程的办法

考核题目中涉及到多线程编程,于是复习了一下系统编程里面的各种概念. 首先,程序是代码,没有活动.通过编译连接之后被加载到内存里运行时,内存活动的就是进程,这里的进程不仅仅是代码段,还包括涉及的数据等.而线程是在同一个进程下的小程序,它们可以"同时"地运行,其中会有一个主线程来控制. 接下来是多线程或着多进程的实现,两者原理基本一样,都是把CPU的时间分片然后进行分配给某个进程或者线程,也就是说在同一个时间只会有一个线程在使用CPU,但是CPU切换线程的频率非常快使得它们看上去是在同一个

【转】Struts2的线程安全 和Struts2中的设计模式----ThreadLocal模式

[转]Struts2的线程安全 和Struts2中的设计模式----ThreadLocal模式 博客分类: 企业应用面临的问题 java并发编程 Struts2的线程安全ThreadLocal模式Struts2调用流程 转载自  http://downpour.iteye.com/blog/1335991 Struts2中的设计模式 设计模式(Design pattern)是经过程序员反复实践后形成的一套代码设计经验的总结.设计模式随着编程语言的发展,也由最初的“编程惯例”逐步发展成为被反复使用

关于线程池运行过程中,业务逻辑出现未知异常导致线程中断问题反思

最近在项目研发中的关于线程池应用过程中由于业务逻辑异常导致的线程中断,但程序未中断导致的脏数据问题  话不多说,在最近最新的一个版本发布过程中,业务需要,我们要定期去给客户预留出可用的资源数据,提供客户使用,在版本即将上线前一周测试过程中,遇到的预留资源数据跟实际数据不匹配,刚开始反复检查代码,通过日志调试一直无果,经过不懈努力,最终终于发现是由于线程在跑业务时,抛出未知异常,当前线程中断,然而主程序并未异常,导致最终响应的数据与实际不符.下面我就简答举例说明下这个问题 1.获取资源数据demo

Unix 线程改变创建进程中变量的值(2)

执行环境:Linux ubuntu 4.4.0-31-generic #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux 1.测试代码: a.c 1 #include <fcntl.h> 2 #include <unistd.h> 3 #include <stdio.h> 4 #include <pthread.h> 5 #include <string.

BCB使用线程删除文件夹中的图片

BCB新建线程DeleteImgThread类,其会默认继承Thread类,然后在Execute函数中编写代码, void __fastcall DeleteImgThread::Execute() { //---- Place thread code here ---- while(!this->Terminated) { //删除.\RecvTmp中的图片 AnsiString JepgDir = ExtractFilePath(ParamStr(0)) + "RecvTmp"

C# 线程调用主线程中的控件

由于项目的需要,最近几天一直在做串口和数据库.由于C#使用的时间不长,所以在编写代码和调试的过程中总是遇到意想不到的问题,比如在使用串口接收数据的时候,在接收数据事件中想把接收的数据放入一个textbox作显示,但是明明非常简单的代码,在编译的时候总是提示有错误.后来查看网上资料,才知道C#还有委托,匿名等等之类的新东西.下面我就把我这几天的经验和大家分享一下.这次就主要说说委托和匿名方法,以后在说说串口使用方面的经验. 先说一下委托的基本概念,委托是一种引用型的数据类型,其实它的概念和C语言的

Android中,子线程使用主线程中的组件出现问题的解决方法

Android中,主线程中的组件,不能被子线程调用,否则就会出现异常. 这里所使用的方法就是利用Handler类中的Callback(),接受线程中的Message类发来的消息,然后把所要在线程中执行的功能交由Handler类来处理.这样就解决了线程出现的问题. 下面测试实例功能为单击图片,图片透明度改变为50,300毫秒后恢复不透明,代码如下: public class Demo extends Activity{ private ImageView changeImg = null;//Im

线程基础:JDK1.5+(9)——线程新特性(中)

(接上文<线程基础:JDK1.5+(8)--线程新特性(上)>) 3.工作在多线程环境下的"计数器": 从这个小节開始,我们将以一个"赛跑"的样例.解说JDK1.5环境下一些线程控制工具(包含Semaphore.CountDownLatch和java.util.concurrent.atomic子包),而且复习这个专题讲到的知识点:同步快.锁.线程池.BlockingQueue.Callable等. 3-1. 赛跑比赛的需求 如今您不仅能够通过我们已经介

线程暴长~Quartz中创建Redis频繁后导致线程暴长

在最近项目开发过程中,在进行任务调度处理过程中,出现了一个问题,它的线程数暴长,从20多个可以到1000多个,如果你的服务器性能好的话,可以到10000多个,太恐怖了,就算你的服务再好,早晚有一天也会被new Redis炸干!哈哈! 解决方法: 使用单例模式减少new redis的次数 对于我们应用程序的线程,如果它持续增长,那么,你就要看一下那么非托管资源是否被释放了,这个要重视起来.