Pulpcode

捕获,搅碎,拼接,吞咽

0%

为啥你的多核手机打游戏没啥提升

Starting

不知不觉2017年就这样来了,虽说这句话说了好多年,自己依然这吊样,但还是不得不说“新的一年,新的自己”。

这篇博客的起因是因为前段时间公司有大神分享了一次《并行程序设计》,里面提到了诸多并行程序的好处和使用方式,虽然我也受益匪浅,但是却令我想起了另一个在编程届流传的笑话,那就是:“一核有难,多核围观。”

类似于网上流传的这张图:

9core

本篇博客将试图讲清楚为什么会这样,顺便解答此篇博客的题目:“为啥你的多核手机打游戏没啥提升。”

多核的意义

你一定有类似概念,即我们的程序都是靠cpu去运行的,你的pc机有自己的cpu,你的手机也有自己的cpu。很多书喜欢把cpu比喻成计算机的心脏,来强调它的重要性。但是这个比喻不是很恰当,相比之下,比喻成“大脑”就会好很多,你的软件(程序)里有如何运行的步骤,而cpu就想大脑一样,控制运行你的程序如何运行。

早期计算机比较简单,程序也比较简单,这样玩没啥问题,但是随着人们需要在在计算机上运行更多的程序时,单个的cpu就不能满足了,这个时候就出现了多核cpu。

我记得高中在《大众软件》上读过一篇文章,讲到INTEL和AMD的纷争,其实AMD一开始是给INTEL打工的小弟,负责给INTEL生产芯片,但虽然是小弟,INTEL给AMD的利润可不少。可就是这样,AMD还是不能满足自己做小弟看着大哥吃肉,所以就独立开始自己搞CPU,后来就越做越大,可以和INTEL抗衡了。

之所以提到这个故事是因为,“小弟”在抢占市场的时候,比“大哥”先做出多核cpu(也就是著名的双核:速龙X2 3600),而且64位的cpu也是AMD先做出来的,顺便说一句,这些所谓的“先”,都是指民企面向市场的。其实这些理论和技术,都是高等学府和军方玩剩下的。

amd64

当然在多核cpu之前还有一种被称为超线程的技术,就是常说的虚拟多核,或者说伪多核,INTEL的奔腾4上最先使用了该技术,能够“让单核cpu同时执行两个线程”,但因为是伪多核,只不过cpu多了一个Logical cpu Pointer(逻辑处理单元),其它的什么ALU(整数运算单元)FPU(浮点运算单元)二级缓存都是被共享的,所以效果不能跟双核相提并论,更坑爹的是,这项技术,要同时有CPU,主板,内存,操作系统和软件多方面支持,也就是说基本没办法使用此技术,所以这件事也被用户骂了很久。

举例来说,如果你的计算机有一个双核的cpu,那么相当于你的计算机就有两个cpu,这意味着,别人的机器同一时刻只能运行一个计算,但是你的机器同一时刻可以执行2个计算,也就比别人快一倍,那么对于市面上那些6核8核的cpu,也就意味这运算速度要比普通的机器快6倍,或者8倍。

比如新出的iphone7使用了A10Fusion是四核,小米5s plus使用了骁龙821也是4核,还有国内的很多8核手机就不提了。

但真的是这样吗?

游戏编程

回到我们博客的题目,游戏程序。

实际上不仅仅是手机游戏,很多pc玩家也经常抱怨,比较大的游戏,跑在自己的多核计算机上,依旧卡的要命。

那是因为这些游戏基本都是“单线程”的。

这么说吧,讲道理,如果你的程序逻辑是多线程的,那么如果它在单核cpu上跑,那就是串行的,如果是在多核cpu上跑,那么它就能并行运行,大大的提升效率。但如果你的程序逻辑本身就是单线程的,那么它只能在一个核上跑,你有再多的核也用不了。

那么为啥写游戏程序的这群程序员不把游戏写成多线程的?

因为太复杂了。

首先游戏编程是我所知的编程领域最复杂的技术之一。很多人举例多线程,多核,多cpu的时候,总是再说,多个人同时在做任务的理想状况,但实际上并行程序的设计远比这个复杂,而且复杂的多,比如有些事情是有先后顺序的,不能并行执行,比如排序,再比如一些先后逻辑,类似你先点餐才能吃饭,并不能让点餐和吃饭同时进行。而且就算并行,还要考虑保持上下文,强一致等等更多的问题,比如你和你妈同时用你的账户取钱,不能在一瞬间看到的金额一样,必须控制一个人取完另一个人才能取。这些事情如果出了问题,排查起bug都难得要死。这些成本考虑在里面,工业上设计的妥协就是把程序写成单线程的。

市面上的游戏引擎,类似cocos,unity等都是单线程的,因为要保证渲染和各种事件的先后顺序复杂度太高,它们不得不设计成单线程的,类似像python,ruby这样的语言,也有类似全局锁GIL存在,来控制复杂度。

当然这里的单线程并不是严格意义上的单线程,开发游戏的那群人,还是会想一些办法利用多核来使用多线程的,比如网络io操作,一些ai,寻路的逻辑等等,但是最重头的主逻辑渲染,依然是单线程的。

所以多核常常是指你的机器可以同时跑更多互不相干的程序。

这下你明白为啥只有跑分软件,能在你的手机上如此畅爽了吧,因为它们就是为充分利用多核而设计的,它们也只能干这个,真实的软件就不能这样用了,这是一种本末倒置,也就说你的多核其实为你的软件提供服务的,但是跑分软件却是专门为你的多核提供服务的。

服务器编程

我是做后端服务器编程的,我们经常提到并行程序设计,其实相比于游戏开发,大部分服务器编程的逻辑还是比较简单的,最起码的,每一次请求都是相互独立的,在这点让服务器并行执行多个请求就很简单,web框架都帮你做了。最近还提出的协程,函数式编程的概念,都让某些并行程序在实现上简单的多。当然只是某些领域而已。复杂起来就真没啥好工具可用了。

瓶颈不在核

如果你学过一些计算机组成或者是优化算法的概念,你一定知道取数速度,cpu>内存>硬盘,而成本和容量 硬盘> 内存 > cpu.所以很多情况下,你cpu算得在快,数据从硬盘读到内存也是慢的。这也就是为什么数据库优化,建立合适的索引是大头,然后才是减少查询量和使用合适类型之类的。我们的程序其实很大一部分耗时,都是读取数据。所以很多人建议你,与其买个什么牛逼的cpu,不如把你的机械硬盘换成固态硬盘。

类似为啥你家都x兆的网,看个片还是卡,因为首先流量的那个M,是以bit为单位,而我们常说的硬盘,是以字节为单位的,8bit = 1字节,笑。。。当然更关键的是,网络请求的大部分耗时,其实通过路由建立通信路径,而不是传输数据本身的耗时,你家的x兆的网,只不过能能使理论流量变大,但是如果找不到数据在哪台主机,还是闲的。

在计算机领域中,常常都是“找到数据在哪最耗时,而非传输数据本身”。