忽如一夜春风来,在地毯式广告和各大媒体的轰炸之下,PC机和基于PC的Server似乎一夜之间进入了多核时代。谈到双核电脑,四核的服务器也已经飞入了寻常百姓家。

Intel和AMD两大芯片厂商花了巨大的力气来推广多核,不能不说有市场利益在驱动。说为什么要多核,当然可以说出一大堆理由:提高效率,降低功耗,半导体技术发展到极限了,甚至还有一个理由叫什么世界本来就是并行的……这里就不多说了,这篇文章主要想说说我自己觉得多核可能会对程序员带来的影响。

在此之前,想先说说多核跟摩尔定律的关系,摩尔同志最早关于摩尔定律的表述是这样的:the number of transistors on a chip doubles about every two years. 所以,最初的摩尔定律其实跟处理器速度没什么关系,只是说处理器上的transistors晶体管数量会翻番。后来的一些年里由于计算机主频速度不断加快,所以摩尔定律就被演绎处理器“主频速度18个月翻一番”的版本。现在呢?计算机的主频速度又上不去了,尤其是笔记本电脑处理器,我2001年买的本子是1G的处理器,如果摩尔定律应验,那现在笔记本处理器速度至少也要8G了,当然这没有变为现实。就在所有人都在疑问摩尔定律会走多远的时候,多核出现了。支持摩尔定律的同志们高兴了,摩尔定律又可以有新的演绎了:处理器核的数量18月或24个月翻一番。虽然core不是transistor,但也八九不离十。可以遇见,不久的将来,8核,16核,32核,64核,128核会争相上市。摩尔定律万岁。

多核主要是体系结构的改变,对于软件开发人员来说,到底多核会给我们带来什么呢?

多核带来的无非是处理能力的提高,最主要是并行处理能力。并行计算这门学问在计算机科学的历史上并不能说是新事务。加速比,阿木到儿’s law(那个人叫什么我实在拼不出来了,只能音译了)等都是并行计算领域的经典内容。很多多核的问题,都可以被化解成为并行计算的问题来解决。所以多核并没有给理论领域带来颠覆性革命,最主要的贡献还是在工程领域。

说虽然这样说,并行计算,SMP,Over,多少有点站着说话不腰疼的意思,具体到如何对多核优化代码,当然还是有很多可表之处。

我认为,对于程序员来说,使用多核首先的第一条,就像很多红头文件说的那样:要提高到思想认识的高度,解放思想,实现思想上的根本转变。这句话可不是空话,毕竟单核串行了那么多年,很多根深蒂固在脑子里的东西都是要淘汰掉的。

举个例子:你写个程序,起两个线程,优先级一个高一个低,OS严格按照优先级调度,在单核情况下,当然我们以为高优先级的肯定会首先执行,事实的确也是这样。但是到了多核就不一定了,两个线程会在两个core上同时跑,尽管他们的优先级的确有高低。

类似的情况还有很多,例如对Cache的使用等等,具体内容咱就不说了,已经有很多资料可以参考。总之就一条,design和coding的时候脑子里面时刻绷紧“并行”这根弦。

同样还是红头文件,讲完了指导思想,就要讲主要任务了。为多核优化的主要任务其实就一个:就是更好的烧CPU。现在谈这个问题或许为时过早,但是最好也未雨绸缪一下。

先看下面一张图吧。这个是我在学院的四核服务器上抓下来的某一个时刻的系统运行情况截图。其中一个core的CPU利用率接近100%,另外三个core的CPU利用率几乎是0。运行的是什么软件呢?呵呵,运行的是Windows的序列号计算器。偶们当然强烈反对计算序列号的行为,在这里拿它当反面教材利用一下。类似“山寨软件”,当然不会做精良的设计了。所以,它并没有很好烧CPU,只烧了CPU的1/4。如果推出并行版算号器,偶相信在4核服务器上算出一个可用序列号的时间会变为1/4多一点,呵呵。

cpu-中国博客网

这给我们一个什么启示呢?就是我们需要尽量让自己的程序中的一些复杂算法,耗时比较多的部分能够多线程并行处理。从而可以更好的烧处理器。读到这里,读者想想自己以前写的代码,无论是java还是.net还是C++,如果放在多核机器上,会出现上图中的情况么?

回到刚才提到的问题,为啥说是未雨绸缪呢?再看上面的图,左下角数据统计,线程数:762。这就说明现在OS中一共有762个线程呢。我即使程序不并行优化,我就猛烧一个core,那另外其它三个core也没闲着,系统中还有761个线程可以在3个core上跑呢。的确是这样,目前在OS下的并行,都是通过多线程实现的。所以,线程数和核的数量关系,就是一个比较有意思的话题。

假设一个场景,如果前文介绍的最新core的数量版摩尔定律能够经久不衰n年,经过数次翻番,Intel 4096个核的处理器终于在某年上市,你兴奋的把它买回来,兴奋的启动Windows XXX(也不知道那时候的Windows会叫什么了)。如果系统中仍然只有762个线程,你会发现,700多个线程,就算每个线程赖着一个核不下台,你的4096个核,还有3000多个核处于闲置空转状态,那就不划算亏大了。

所以,现在的双核,四核情况下,不并行优化自己的代码,可能还没啥,毕竟其它程序也在创建线程,也在烧core,但是当Core的数量大于系统中线程的数量的时候,不优化就不是程序效率的问题,是浪费地球资源的问题了。记住了,多核优化的主要任务:多线程,并行,”烧Core”。

谈到这里,一直说解放思想,或许应该“步子迈的大一点”。反思一下“用多线程来实现并行优化”这个问题的本身有没有问题。

相信有过多线程编程经验的人都知道,程序中线程的数量与程序的复杂度之间的关系,绝对不是线性这么简单。如果你的程序中有20个以上的线程需要彼此共享数据,彼此等待,彼此同步,彼此锁来锁去,如果你能坚挺不晕过去那一定是喝了脑白金健康品了。那把问题扩大化一下,在未来4096个核上运行一个复杂算法,按照现在的技术实现方法,至少要创建4096个线程来一起跑,乖乖隆滴冬,你想过在自己的程序中调用4096次CreateThread,创建出来那么多线程,然后你再来管理他们么?

或许,我们应该问的是这样一个问题,“多线程到底是不是解决并行优化应该使用的方案”?

我觉得,用线程这种方式来管理并行,是比较原始的方式。就像当年高级语言出来之前,用汇编直接操作CPU一样,高级语言横空出世,就再也不用程序员去记忆复杂的指令,管理复杂的处理器细节了,程序本身的规模也可以逐渐扩大。真正能够把多核的威力发挥出来的,应该是编程语言或编译器的革命。当某一天某种编程语言或者编译器或者某种OS机制出世,程序员再无需关心如何自己动手烧Core的时候,程序员只需要关注自己的业务逻辑,烧core这种底层的事情会由系统软件自动完成的时候,多核时代才能真正到来。一言以蔽之,我们需要的,应该是一种隐式的并行机制,而不是显式的自己手动管理4000多个core。

在这方面,OpenMP给我们看到了一点未来。在for循环上面加一条#pragma omp for xxxxx,就可以自动把这个循环并行化了。至少这对于用惯了Windows Thread,pthread的程序员来说,它提供了一种不一样的思路,这种思路,或许才是并行计算和多核的未来。

结束语:我的双核笔记本跑Windows Vista的确不错,运行多个ajax的网页依然奔跑如飞。我希望下个学期计划会在学院的几门课程中增加一些多核的内容,敬请关注。