怎样做颠覆式创新?

关于怎样做颠覆式创新,普林斯顿的李凯教授给出了四个要素:

(1)找到最好的合伙人

(2)理解市场需求(例如你是卖维生素还是抗生素?)

(3)紧跟技术发展趋势(例如多核时代来临时,你的软件一定要充分利用多核并行)

(4)产生一个新的产品类别(比老产品好10倍甚至20倍,才能颠覆已有方案)。

何为颠覆式创新?你的产品需要能取代高中低端的所有已有产品,这就是颠覆式创新。例如用3个2U服务器的重复数据删除解决方案取代27个机柜的传统方案。这意味着你的产品比已有产品好10倍到20倍。

关于颠覆式创新,彼得·蒂尔也说过:“我判断一个项目一般有三个标准:人、技术、商业模式,必须三样同时具备。

首先对人来说,我觉得我们不够重视团队的结合。可能一个团队的成员背景、履历都很厉害,但这些人在一起工作时是怎样的却是另一个问题,他们也许都很有才华,认为自己比别人聪明,而风险在于有一个“很大的自我”的人也许很难在一起工作,有时你能看到几个很优秀的人组成了一个很糟糕的团队。所以我会问这些人怎么相遇的,在一起多久了,之前的关系等等。

技术方面,如果只是比别人好10%或20%是不行的,要好上10倍、20倍。

还有一个标准是商业战略。对硅谷的投资者来说有太多的牛人、太好的技术,但在商业战略上是比较缺乏的。在我的理念中,要成功,首先你要能够实现垄断,你要有一个专属于你自己的类别,不是说你很快就有一个非常大的市场,而是可以从一个较小的市场做起,在早期就有一个较高的使用频度,人们很喜欢你的产品、推荐给朋友。”

 

下一代大数据分析技术

原文发表于《程序员》杂志2013年第2期.

文 / 陈冠诚

随着以Hadoop为代表的大数据分析技术的普及,大数据的商业价值得到深入挖掘,并开始在互联网、零售、医疗、物联网等多个行业里成为商业变革的主导力量。Facebook最近就发布了名为Graph Search的新型社交搜索产品,基于海量的社交关系网络及“Likes”行为数据,为用户提供个性化的社交搜索服务,该产品被认为将是Google搜索业务的重要竞争对手。在电子商务领域,淘宝的数据魔方就是一个基于大数据分析的典型产品。数据魔方基于淘宝所掌握的大量消费数据提供各种各样的分析服务,例如展示消费者的购物习惯,地域分布,年龄分布,热销排名等,为淘宝卖家提供了非常有价值的分析数据。然而,这些现有的大数据分析技术处理的主要对象仍集中于文本数据,例如社交图谱,搜索关键字,商品数目,店铺、商品浏览记录,成交、收藏、评价记录等等,却没有涵盖一类非常重要的数据:多媒体。

实际上,多媒体数据的数据不仅规模远远超过文本数据,其商业价值也毫不逊色。以全球流量最大的网站Youtube为例,它在07年一年所消耗的网络带宽就等同于整个互联网在2000年的全部流量。另一方面,多媒体数据的来源也是异常丰富。仅以手机为例,手机的摄像头、麦克风可以产生丰富的图像、视频、语音数据。除此之外,社会中的各种监控摄像设备、医疗图像设备、物联网传感设备、卫星图像等都能产生大量的图像、视频数据。而多媒体相对于文本数据更有其得天独厚的优势:丰富的多媒体数据对人的感官刺激远胜过纯文本数据。以新浪微博为例,微博中被大量关注和转发的微博大都含有图片、视频等链接;相反,纯文字的微博受关注的程度还是会差不少。同样,微信以语音作为主要的信息载体,一举与纯文本的短信形成差异化竞争优势,再加上产品的社交因素而一炮走红,现在大家经常能在街上看见与手机上的微信好友对话的用户。在零售行业,基于图像的大数据分析也将打开一片新的市场。例如在一个大型的购物中心,我们可以对人流的视频数据进行分析,从而对消费者的购物习惯、逛街顺序等信息进行充分挖掘,从而有针对性地设计相应的促销方案、货架摆放规律等等。在安防行业,基于对视频数据的实时分析,我们可以监控潜在的安全隐患(例如检测出消防通道被占用需要及时清理),大大提升安全措施的响应时间。可以预见,基于多媒体数据的大数据分析将对互联网、零售、安防、生物医药等在内的众多领域发挥重要的作用。

在笔者看来,基于多媒体数据的大数据分析主要的技术难点就在于数据量和算法复杂度大大增加。Google在2012年有一项曾引起广泛关注的研究成果:他们使用了一千台电脑的一点六万颗处理器核组建了一个机器学习神经网络,花了三天时间用来自Youtube中截取的1000万幅图像来训练该神经网络,从而使得该网络可以自主学习并形成了“猫”这个概念,最终成功地识别出猫的图像。从这个例子中我们可以看到,要对海量图像、视频进行分析所需要的机器规模确实对计算资源和软件算法提出了极大挑战。好在视频、图像、语音处理并不是一个什么崭新的领域,这些方向都有很多的技术积累。笔者认为,真正的挑战可能在于如何将现有的多媒体处理技术扩展到大规模数据上去,毕竟对小规模数据有效的算法可能在处理超大规模的数据时会遇到从未有过的挑战。但是笔者也相信,基于多媒体数据的分析技术也一定会在未来得到蓬勃发展,并为用户创造新的价值。

C++ AMP异构并行编程解析

原文发表于《程序员》杂志2012年第4期,略有改动。

/ 陈冠诚

微软在今年2月份的GoingNative大会上正式对外发布了C++ AMP(Accelerated Massive Parallelism)开放规范。C++ AMP是微软于11年6月推出的一个异构并行编程框架,从Visual Studio 11开发者预览版起,微软正式提供了C++AMP的支持。C++ AMP的目标是降低在由CPU和GPU共同组成的异构硬件平台上进行数据并行编程(data parallel)的门槛。通过C++ AMP,开发者将获得一个类似C++ STL的库,这个库将作为微软concurrency namespace的一部分,开发者既不需要学习新的C++语法,也不需要更换编译器就能够方便地进行异构并行编程。本文主要介绍C++ AMP的设计原则和语法规则,并将其与CUDA和OpenCL这两个已有的异构并行编程框架进行了对比,希望对大家了解异构并行编程有所帮助。

C++ AMP设计原则

随着CPU由单核向多核转移,多核计算成为了近几年的热点。另一方面,GPU编程也经历着一场变革。传统意义上,GPU一直是作为图形图像专用处理器而存在。然后,因为GPU拥有比CPU还要强大的浮点并行运算能力,我们是不是能让GPU来完成一些通用的计算任务呢?答案是肯定的,例如科学计算中就需要大量的用到浮点计算。在这样的背景下,我们可以将并行计算从单纯的在多核CPU上做,扩展到在多核CPU与GPU共同组成的异构硬件平台上来。除了多核与GPU通用计算的快速发展职位,云计算更成为软件开发的一个重要趋势。实际上,云端的每一台服务器都可以是由多核CPU和GPU共同组成的异构硬件平台。微软的Herb Sutter介绍说:“我们认为多核编程、GPU编程和云计算根本不是三个独立的趋势。实际上,他们只是同一种趋势的不同方面,我们把这个趋势叫做异构并行编程”。进行异构并行编程需要一个统一的编程模型,这就是微软推出C++ AMP的原因。

微软决定另起炉灶,推出C++ AMP这样一个全新的异构并行编程模型的原因很简单,他们认为这个编程模型必须同时具备下面这六个特征,而目前已有的CUDA和OpenCL并不同时满足这些需求。

  • C++而不是C:这种编程模型应该利用好C++丰富的语言特性(例如抽象,模板,例外处理等),并且不会牺牲性能,因此我们不能像OpenCL一样只是C语言的一种方言;
  • 主流: 这个编程框架应该能被成千上万的开发者所使用,而不是只被少数人所接受。一个立见分晓的检验办法是:用该编程框架实现GPU上的hello world是只需要几行代码,还是需要几十行才行?
  • 最小的改动: 这个编程模型应该只需要在C++上进行最小的改动就能够实现应有的功能。通过一个非常小的、具有良好设计的语言扩展,我们就可以把绝大部分复杂的实现交由运行时系统/库去完成。
  • 可移植的。这种编程模型应该让用户只需要一个二进制可执行文件就可以在任何厂商的GPU硬件上面运行。目前我们使用Direct Compute来实现Windows上所有支持DX11的 GPU上的C++ AMP编程模型,但是未来我们会根据用户的需求在其他异构硬件平台上做相应的实现。
  • 通用且不会过时。C++ AMP目前针对的是GPU并行计算。但是我们希望,将来C++ AMP的程序可以无缝的扩展到其他形式的计算单元上去,例如FPGA,云端的CPU/GPU处理器等等。
  • 开放。微软将吧C++ AMP做成一个开放标准,我们鼓励第三方在任何硬件和操作系统上实现C++ AMP编译器和运行时系统。目前AMD和Nvidia都已经声明将会支持C++ AMP。

C++ AMP介绍

下面让我们通过一个简单的程序来了解一下C++ AMP的一些语法规则。首先我们需要引用amp.h这个头文件。C++ AMP中的模板都在concurrency这个命名空间内,所以也需要引用。在C++ AMP中主要有array和array_view这两种数据容器。这两者主要的区别在于array类型的数据在创建时会在GPU显存上拥有一个备份,在GPU对该数据进行完运算之后,开发者必须手动将数据拷贝回CPU。与之相比,array_view其实是一个数据结构的封装,只有在它指向的数据被GPU调用时才会被拷贝到GPU上进行相应的计算。从下例中我们看到,声明array_view数据时需要提供两个模板参数:array_view元素的类型和数据结构的纬度。因为aCPP,bCPP和sumCPP都是一维数组,因此我们在声明时传入int和1两个参数。

接下来就是最重要的计算部分了。parallel_for_each这个方法就是执行在GPU部分的代码的入口。可以看到,parallel_for_each有两个参数,第一个名为sum.extent的参数是用于描述并行计算拓扑结构的对象。通过这个变量,我们指定有多少个GPU线程来并行执行该计算任务,以及这些线程的排列方式。Sum.extend可以理解为按照sum的数据纬度来分配相应数目的GPU线程。Parallel_for_each的第二个参数是一个名为“[=] (index<1> idx) restrict(amp)”的lambda表达式。方括号里的“=”代表了表示lambda表达式的捕获列表。具体来说,“[=]”表示lambda里捕捉的变量按照传值的方式来引用。该for循环的主要参数就是index<1> idx了,它其实代表的是GPU线程的编号。因为之前我们已经通过sum.extent定义好了GPU线程的数量和拓扑结构,因此这个index参数代表的就是一维的数组,即从0到4共5个数。最后一个参数restrict(amp)用来表示parallel_for_each的函数体运行在默认GPU设备上。当然我们也可以定义出amp之外的其他的语法约束,具体的内容请大家参考[1]中的内容。在这之后就是循环体了。这个例子的循环体非常简单,就是让GPU用5个线程并行地把数组a和b中的元素依次相加并存到sum数组中去。

#include <amp.h>
#include <iostream>
using namespace concurrency;

void CampMethod() {
    int aCPP[] = {1, 2, 3, 4, 5};
    int bCPP[] = {6, 7, 8, 9, 10};
    int sumCPP[5] = {0, 0, 0, 0, 0};

    // Create C++ AMP objects.
    array_view<int, 1> a(5, aCPP);
    array_view<int, 1> b(5, bCPP);
    array_view<int, 1> sum(5, sumCPP);

    parallel_for_each(
        // Define the compute domain, which is the set of threads that are created.
        sum.extent,
        // Define the code to run on each thread on the accelerator.
        [=](index<1> idx) restrict(amp)
        {
            sum[idx] = a[idx] + b[idx];
        }
    );

    // Print the results. The expected output is "7, 9, 11, 13, 15".
    for (int i = 0; i < 5; i++) {
        std::cout << sum[i] << "\n";
    }
}

从这个例子我们可以看到,使用C++ AMP进行异构多线程编程确实是很容易的。开发者如果熟悉C++的话,一般只需要很短的时间就可以上手实现相应的功能。

CUDA、OpenCL与C++ AMP

其实在C++ AMP之前已经有了两个异构编程框架:CUDA与OpenCL。CUDA(Compute Unified Device Architecture)是显卡厂商Nvidia于2007年推出的业界第一款异构并行编程框架。在Nvidia的大力支持下,CUDA拥有良好的开发环境,丰富的函数库,优秀的性能。但是CUDA只能被用于在Nvidia的显卡上进行异构编程,有先天的局限性。OpenCL (Open Computing Language) 是业界第一个跨平台的异构编程框架。它是Apple领衔并联合Nvidia,AMD,IBM,Intel等众多厂商于2008年共同推出的一个开放标准,由单独成立的非营利性组织Khronos Group管理。与C++ AMP类似,OpenCL作为一个开放的标准,并不局限于某个特定的GPU厂商,从这点上来看,Nvidia自己独家的CUDA显得很封闭。我们可以把OpenCL在异构编程上的地位与OpenGL和OpenAL类比,这两个标准分别用于三维图形和计算机音频。

因为CUDA与OpenCL比C++AMP更接近硬件底层,所以前两者的性能更好,然而与C++ AMP的易编程性却要优于CUDA和OpenCL。与C++ AMP基于C++语言特性直接进行扩展不同,OpenCL是基于C99编程语言进行的相关修改和扩展,因此C++ AMP比OpenCL拥有更高层次的抽象,编程更加简单。在CUDA和OpenCL中,kernels(运行在GPU上的代码)必须被封装成特定函数,而在C++ AMP中,代码看起来整洁的多:我们只需要使用for循环中内嵌的lambda函数就能完成异构并行计算,而且它的内存模型也在一定程度上被大大简化了。

那么在OpenCL、CUDA 与C++ AMP之间,开发者该如何选择呢?

1)  如果你只需要在Windows平台上进行异构编程,并且看重易编程性的话,C++ AMP无疑是最好的选择。依托于Visual Studio这个强有力的开发工具,再加上基于C++这一更高层抽象带来的先天优势,C++ AMP将为Windows开发者进行异构编程提供良好的支持。

2)  如果你只需要在Nvidia的GPU卡上进行异构编程,并且非常看重性能的话,CUDA应该是第一选择:在Nvidia的强力支持下,CUDA在Nvidia硬件上的性能一直保持领先,许多学术研究表明OpenCL与CUDA的性能相差不大,在一部分应用中CUDA的性能稍微好于OpenCL。同时CUDA的开发环境也非常成熟,拥有众多扩展函数库支持。

3)  如果你更注重不同平台间的可移植性,OpenCL可能是目前最好的选择。作为第一个异构计算的开放标准,OpenCL已经得到了包括Intel,AMD,Nvidia,IBM,Oracle,ARM,Apple,Redhat等众多软硬件厂商的大力支持。当然,C++ AMP本身也是一个开放的标准,只是目前只有微软自己做了实现,将来C++ AMP的跨平台支持能做到什么程度还是一个未知数。

其实从编程语言的发展来看,易编程性往往比性能更加重要。从Java和.Net的流行,到脚本语言的崛起,编程效率无疑是最重要的指标。更不用说开发者往往可以通过更换下一代GPU硬件来获得更好的性能。从这点来看,C++ AMP通过降低异构编程的编程难度,实际上也是推进了异构编程的普及。下面我们需要看的就是C++ AMP是否能成为真正的业界标准,而不仅仅局限于微软自己的平台,微软这次开放C++ AMP标准的行为也正是为了推广C++ AMP在业界的普及。

总结

目前整个业界的异构硬件体系结构仍然处于快速演变之中。可以看到,许多厂商的处理器正在尝试融合CPU和GPU(例如AMD的Fusion,Intel的Larrabee和Nvidia的Tegra3都融合了CPU和GPU)。如果将来的处理器上集成了CPU和GPU,并通过同一条总线使它们与内存直接相连的话,我们就不需要向今天这样把数据在CPU和GPU之间搬来搬去了。随着异构硬件的发展,与之相对应的异构编程框架在需要随着演变。可以预见,今天我们看到的CUDA,OpenCL和C++ AMP都只处于一个初期形态,将来它们还会有很多新的变化。但是有一点我们可以肯定:将来的异构编程一定会比现在更加容易。

参考文献

[1] Overview of C++ Accelerated Massive Parallelism. http://msdn.microsoft.com/en-us/library/hh265136(v=vs.110).aspx

[2] C++ AMP实战:绘制曼德勃罗特集图像. http://www.cnblogs.com/Ninputer/archive/2012/01/03/2310945.html

云计算时代的多核开发

注:原文发表于《程序员》杂志2011年第12期,略有删改。

云计算和多核这两大趋势正对软件开发者产生重大影响。近几年,多核逐渐成为主流:随着提升CPU核心频率越来越难,处理器厂商选择了更加容易实现的多核方案来继续提升硬件的性能。进入后PC时代,移动处理器也同样面临着性能的提升与功耗的控制这两大挑战,为了满足提升性能与控制功耗的需求,多核也正成为其以后发展的方向。另一方面,云计算也渐渐成为软件开发的大势。在云计算的生态系统中最主要的设备是“端”和“云”。所谓端包括移动设备(智能手机,Pad等)和传统的PC,尤其是前者;而云指的就是由高性能服务器组成的大规模集群,它们向端设备提供各种服务支持。在云计算时代进行多核开发会是一幅什么样的场景?这两大趋势彼此会有什么样的影响?我们不妨先回顾一下在大型机和PC机时代软件开发的历史。

多核上开发将更加容易

在大型机时代,计算机非常昂贵,用户需要分时共享同一台大型机。计算资源的稀缺使得那时候的软件开发者必须高效地利用每一个处理器时钟周期,因此他们大都使用汇编、C等非常底层的语言来进行软件开发,而算法的效率是他们最关心的问题。在之后的几十年中,计算机硬件变得越来越廉价,软件开发者越来越不需要关心软件的性能。以主流的互联网应用为例,现在的开发大量使用成熟的框架来帮助自动生成大量的代码。就拿Django这个流行的Web开发框架来说,它的设计原则是“focuses on automating as much as possible and adhering to the DRY principle: Don’t Repeat Yourself.”开发者最核心的目标已经变成了如何用最少的代码,最快的速度将自己的点子转为成可用的软件产品并推向市场。“市场投放时间”已经取代“处理器时钟周期”成为软件开发的关键指标。在过去的几十年里,正是因为硬件一直在按照摩尔定律稳步地发展,所以开发者不再需要时刻关注软件的性能,而是将其注意力转移到更为重要的开发效率上,这点在近十年来Java、Python、Ruby等高级语言的兴起上就可见一斑。多核的出现,将硬件的细节再一次暴露在程序员的面前。如果想利用好多核,程序员必须手动的处理同步、死锁、数据竞跑等疑难问题,这极大的降低了软件开发的效率。现有的生产工具(多核开发框架、开发工具)远不能满足生产力(软件开发效率)的发展需要,还有很大的发展空间。可以预见,不久的将来更简单易用的多核开发框架将不断涌现,在多核上进行并行编程将变得越来越容易。

那放在云计算的大背景下,多核开发又会有怎么的发展呢?让我们先来看一看在“云”和“端”上的多核发展趋势。

“云”和“端”的多核趋势

据IDC预测,以智能手机和Pad为代表的移动设备在2013年将达到3.9亿台的出货量;相对的,传统PC机、笔记本和服务器加起来的出货量预计为4.4亿[1]。移动设备的日益流行将让更多的开发者转向移动平台。与此同时,云将为端设备提供更多的服务支撑。那么云和端上的多核将如何发展呢?

如上图所示,从2012年开始双核的手机/平板将成为主流。因为受到功耗的限制,移动设备上的处理器核数并不会迅速增长。实际上,移动设备将会越来越多地依赖专用硬件加速器来提供高性能、低功耗的解决方案。GPU(图形处理器)就是一个很好的例子。在手机和平板上观看高清电影、玩高分辨游戏时会我们可以依靠专用的图形处理器来进行图像渲染、高清解码等操作,这种解决方案相比于使用更多的通用处理器核数来说能提供更高的性能功耗比。从开发者的角度来讲,产品设计、用户体验才是现阶段移动开发者最关注的问题,而如何利用并行编程的方式提升移动应用的性能在短期内还不会是最主要的关注点。不可否认的是,越来越多的移动应用将通过并行化的方式提供更绚丽的3D渲染,更流畅的用户体验以及更丰富的特效(尤其是游戏类应用)。

与此同时,云端服务器的处理器核数将继续以每18个月翻一番的速度增长。在多核出现之前,软件开发者无需担心软件的性能,他们唯一需要做的就是“等”:等到下一代处理器出现时,软件对性能的需要就能得到满足。这个免费的午餐在多核到来之后不复存在:单纯靠增加处理器的核数并不能提升单线程程序的性能。换言之,我们必须通过并行的方式来提升“串行”应用的性能。但是如果我们所关心的问题不再是如何提升单线程的性能,而是如何利用更多的核来处理已经并行化的应用(例如MapReduce),那么核数的增加不就能继续“免费”地提升此类应用的性能吗?从这个角度来看,云端的应用与多核有点天生一对的意味。举例来说,以Hadoop为基础的大规模数据处理通过并行执行Map和Reduce来有效的对海量数据进行有效的处理。这种数据并行(data parallel)的模式关心的不再是单个Mapper或者Reducer的性能,而是所有Mapper、Reducer的吞吐量。如果需要处理的数据增加了,那么我们一般只需要增加更多的机器(即更多的处理器核数)就能达到所需的性能。

当谈到并行计算时,我们必须区分好两种完全不同的应用:并行(Parallel)与并发(Concurrency)。所谓并行是指两个或多个task同时执行用以完成同一个计算任务,例如使用两个线程来并行地完成矩阵乘运算。所谓并发是指两个或多个task同时执行,但是彼此相互独立、分别在完成不同的计算(这里的task不仅仅局限于线程,它也可以代表纤程、进程等)。而对云计算来说,云端所需要处理的请求大都是并发任务,因为不同的终端请求彼此大都是相互独立的。想象一下数千用户同时使用Google Docs编辑文件,此时服务器端所需要处理的就是数千个并发请求,这些独立的请求能非常自然地把服务器上的多核利用好。由此可见,在云计算的大背景下,大量存在的并发应用能天然的利用好云端的多核,通过并行的方式来利用好多核并不是那么的重要。

人人都是并行程序员?

在多核出现之初,许多业界人士都惊呼狼来了,人人都需要掌握并行编程。殊不知并行编程这项技术早在二三十年前就已经存在了,只不过当时大都是由搞高性能计算的一小群人会并行编程,而随着多核的普及并行编程的神秘面纱也逐渐向大众展开。幸运的是,在云计算的大图下,多核的应用场景以及与高性能计算领域大不相同。高性能领域关心的主要问题是如何用更多的处理器核心来更快的完成同一个任务,例如天气预测,地震模拟等。而在云计算领域,我们面临的主要难题是如何满足众多端设备的并发请求,这些请求彼此大都独立,因此处于云端之上的开发者已经不太需要担心如何用并行编程来解决他们所面临的问题。

如上图所示,在Google趋势中“云计算(cloud computing)”这个关键词的热度一直都处在上升趋势中,而“多核(multicore)”的热度一直都比较平稳。随着移动互联网的兴起,Android和iOS开发的热度也已经超过了多核。并不是所有的程序员都需要关心如何进行并行编程。在云计算的大背景下,并发应用能与多核很容易地结合在一起,将云端的多核利用好。

移动设备进入多核时代!

Nvidia最近发布了代号为Tegra 2的新一代双核移动处理器,移动设备即将进入多核时代。该款处理器由两个基于ARM Cortex A9的核心及其它视频音频图形专用核心(可看成Accelerator)组成,是一个典型的异构(Heterogeneous)平台。这个平台的关键特征有两个:低功耗(比高频单核的处理器耗电小),高性能(异构平台的性能优势)。

我之前也讲过为什么我们要迁移到多核平台,简单来说,继续提升核心频率及电压的办法会让处理器的功耗呈指数级增加,此时的功耗会难以让人接受;而在晶体管数目持续增加的前提下,工业界自然就(被迫)选择了更加容易实现的多核方案来继续提升硬件的性能。这个趋势也即将体现在移动处理器上。

Nvidia的白皮书《The Benefits of Multiple CPU Cores in Mobile Devices》中提到了几个多核对移动应用带来的好处:

1. 更快的网页加载速度

现在的网页内容越来越丰富,也越来越复杂。HTML5,Flash,Javascript,视频等内容的呈现都需要强大的处理能力。Nvidia提供的测试数据表明Tegra 2的Javascript性能提升了1.5~2倍,网页平均加载速度提升了46%。事实上Firefox,Chrome等桌面浏览器都已经采用了多线程,而Android浏览器,Safari等采用的Webkit内核也已经实现了多线程。在浏览器已经并行化的前提下,多核移动处理器自然能提供更快更丰富的网页渲染体验。

2. 更低的功耗及更高的性能瓦特比

对多核来讲,任务调度及电源管理算法是提升性能瓦特比的关键。Tegra 2能通过如下几点降低功耗:
1)把任务平均分配到两个核心上,这样每个核心都不必跑在最高频率/电压上,而只需要以较低的频率/电压就能完成任务,从而节省功耗
2)如果要执行的任务是高度并行化的,Tegra 2就能更快的完成这个任务,从而更快的进入超低功耗待机模式,节省更多电量
3)如果任务只需要一个核心的话,其他计算单元可以被关闭从而节省电量

续航能力一直是手机、Tablet等移动设备的关键问题之一,在电池技术没有突破性进展的今天,我们只能寄希望于硬件/软件上的优化手段来降低功耗了。

3. 提升游戏体验

Tegra 2的图形处理单元叫做Ultra Low Power (ULP) GeForce GPU,性能应该很不错。现在的一些主流游戏引擎早已经完成了并行化(多线程分别用来完成渲染,音频,网络,解码,碰撞检测,透明等任务)。白皮书中提供的测试数据表明虚幻3引擎在Tegra 2双核心上快了将近70%。一个值得注意的地方时很多游戏引擎是通过task parallelism的方式以适应不同的处理器核心数目,这说明基于这些引擎的游戏可以在几乎不修改程序的情况下在以后的4核乃至8核移动平台上取得更好的游戏体验。游戏在最受欢迎的移动应用中还是占了大头的,所以多核对移动游戏应用的影响会非常大。

下面是一些主流游戏引擎使用的线程数:
Game/Engine(Number of Threads)
Unreal Engine 3(4+)
Id Tech 5(6+)
Frostbite(14)
Civilization 5(12)
Mafia 2(4)
Crysis(8)
Uncharted 2(8)
Killzone 2(8+)

4. 更平滑的用户体验及更快的多任务处理能力

多任务处理在手机/Tablet上都非常常见。当你一边听着歌,一边下载电影,一边上网冲浪时,多核处理器就能帮你把这些任务分配到不同的核心上进行处理,从而给你提供更好的更平滑的用户体验。我记得iPad上的一些电子杂志的界面响应速度是个很大的问题,因为渲染速度太慢了,性能更高的多核平台就能提供更快的处理速度,提升用户体验,当然,这个前提是该程序能充分利用好多核。

想到这我还要插一句题外话。iOS一开始不支持对第三方程序的多任务处理功能其实主要是因为iPhone/iPad上内存有限(256MB)且没有硬盘(即没有swap),具体可参考Robert Love(该大牛现在在做Android)这篇《Why the iPad and iPhone don’t Support Multitasking》;至于Android怎么解决多任务处理的可以参考这篇《Multitasking Android Way》(想看这两篇都要会功夫,你懂的)

移动设备的多核时代已经到来,移动开发者们,你们准备好了么?

Erlang User Conference 2010见闻(兼谈程序员职业生涯)

1. Erlang User Confernece 2010

这是我第一次参加关于Erlang的技术大会,总来的说收获非常大,不管是技术上的还是非技术上的都是如此。首先不得不说的是会议举行的地点。我从别人那得知之前的会议一直都是在Ericsson的总部大楼举行的,但是因为参会人数越来越多,好像是从去年开始就转移到市中心一个很有历史的电影院ASTORIA举行了。由于这个举办地是电影院的缘故,从去年开始EUC就开始有电影海报了!去年海报是由哈利波特改的,今年的是星球大战。去年那张如下,有意思吧?

Erlang-the-Movie

海报上面的四个人是Erlang最早的设计者们:Joe Armstrong, Mike Williams, Robert Virding还有当时的团队经理Bjarne Däcker。有了海报没有电影怎么能行?点这里观看Erlang – The Movie

因为我赶早乘火车去的斯德,所以我到的时候已经快9点了,大会即将开始。在去之前我就很期待能见到Joe Armstrong本人,结果意外的是在签到处我就见到Joe本人了!不知道为什么,他出现在我面前时的形象与我之前想象的一模一样,后来我想明白了,根本原因在于他穿的就是他那件非常眼熟的紫黑线衫!哈哈!Joe爷爷人非常开朗,时不时从他坐的地方传出爽朗的笑声,此为后话。因为会议即将开始所以我就赶紧进去找座位坐下,正好赶上Bjarne Däcker在致开幕辞,这是每年的传统了。仔细看了下我的签到卡,这已经是第16届Erlang大会了!

Klarna无疑是这届大会最吸引眼球的公司。开幕第一个Talk就是关于他们怎么使用Erlang相关的工具来解决他们的CodeManagement,Translation,Testing等问题的。Klarna有两个中国程序员,我见到其中之一的Wang Jia。Klarna是由三位瑞典银行家在05年创立的公司,提供第三方电子支付解决方案。他们最早的开发者就是从当时提供Erlang咨询的公司(其实也是Ericsson前员工)跳出来的。传闻说当时创始人提出业务需求后,他们说这个太简单了,用Erlang几天就开发出来了,虽然最后花了大概一个礼拜,但是可见Erlang开发效率之高。现在他们应该是Erlang程序员最多的公司,而且随着业务的增长他们的开发团队也在快速扩张。一年前他们只有20个左右,现在已经解决60人了,听说还要继续招人。Good for them! 我还见到另一个在Mobile Art做Erlang开发的中国人张浩,他已经用Erlang做开发3年多了。我们聊了很多关于职业发展的问题,非常有收获。

此次大会的slides和talk都可以在这里下载

2. 关于职业生涯

除技术之外我最大的感触就是看见一群爷爷级的人物仍然热衷于参加这样的技术盛会,让我很有编程编到老的冲动。Joe Armstrong老爷子是1950年生的,早年在英国念物理PhD,后来自己钱花光了,就跑去了爱丁堡做人工智能了。他的导师Donald Michie在二战时跟图灵一起工作过,所以收藏有图灵所有的论文。Joe就在满是图灵的论文的办公室里工作了整整一年多,难怪如此之牛。做研究讲究家谱,大师之所以成为大师还是需要一些机缘在里面的(当然,独力开创一片新天地的神牛除外)。关于Joe的更多趣闻可以看《Coders at Works》,中文版应该快出版了,但是如果有条件的话还是推荐大家读英文版,边学大师的经验边学英语,一举两得,岂不快哉?如果大家好奇Joe是怎么修炼到大师级的,他自己一句话很有代表性:“So I would characterize that period, which took 20 years, as learning how to program”。这句话的上下文我就不详述了,简单地说你可以理解成他花了20年学会了如何编程(注意,这个“如何编程”可不是指精通C++之类的)。这说明要想成为大师,没有十几二十年的功力肯定是不行的。十年学会编程不是空谈,而是实实在在的。说到程序员的基本功,我必须要站出来批评一下《Coders at Works》此书在豆瓣的一个不负责任的书评,这位同学说“去他的算法内功基础,对于程序员实用主义才是王道”,这完全是误人子弟,而且可悲的是这个观点竟然有很多人支持。表面上这句话好像抓住了“实用主义”的大旗,但是这位同学却借此抨击算法基本功的重要性,实在是荒谬。(Update:该同学已经把标题改掉了)就拿Google Fellow Jeff Dean来说,他绝对算得上是实用主义的大师了吧?可是如果你去看看他关于Google整个系统架构演变过程的讲座,你就会发现把Google的那些诸如MapReduce、GFS之类的看家法宝化繁为简之后都可以还原成最基本的算法、数据结构之类的问题。Google整个架构的发展是根据需求的变化而发展而来的,MapReduce之类的不就是在遇到需要解决大规模并行编程这个问题时产生的实用的解决方案吗?可是,如果没有扎实的基本功它能被设计出来么?哪一个大师不是编程十几二十年以上?他们的基本功可能差么?想真正成为杰出的程序员,没有扎实的基本功是绝对不可能的,因为你会发现当你需要面对一个没有现成的解决方案的问题时,你的基本功就是最可信赖的法宝。

我在国内念书时确实也不知道天有多高,国内IT界有多浮躁,到了瑞典之后我有机会在Nema Labs(创业公司),Ericsson(大公司)实习,跟我的导师Per Stenström学习,与John Hughes这样的大师交流,眼界真的开阔了很多。浮躁在中国是很普遍的社会性现象,就拿程序员职业生涯发展来说,中国现在很难找到有十几二十年经验的超级程序员,为什么?因为他们都转到管理方向去了,当CEO,CTO去了。我觉得这是由中国“官本位”的社会思想导致的。大家都觉得管人的比被管的等级高,要拿更高的工资,这实在是大错特错。实际上在外国公司里终身从事技术工作的超级工程师大有人在,而且这些超级工程师的工资往往比他们的Manager高得多。在瑞典,做基站的超级工程师时薪4K多克朗的都有(克朗跟人民币几乎等值,绝对真实),50W年薪的比比皆是,这样的待遇还会让你觉得当一辈子工程师没前(钱)途吗?我觉得走管理路线本身没有错,前提是你确实喜欢管理,善于交流,适合你的性格,而不是为了职业发展“被迫”往管理方向转。在现代企业中,管理者与被管理者本身没有高低贵贱之分,只是职能不同罢了。最顶级的程序员不仅受人尊重,更可以拿高薪。可惜国内社会风气普遍浮躁,这样的状况想要改变还需要很长时间。从供需的角度来讲,超级程序员的身价是由市场需求决定的。就拿华为来说,我上次跟他们在瑞典这边的一位技术负责人聊天时了解到他们在Kista最喜欢有十几年以上经验的超级工程师,因为这样的人才国内根本招不到。为什么他们需要招这样的人?因为华为的竞争对手也是世界级的企业(例如Ericsson),这个时候科技创新就是企业最重要的核心竞争力,自然就需要最顶级的工程师才能在竞争中胜出。我们看到的Google花250W美金挽留一位女工程师的例子(未经证实,可能是Facebook负责招聘的人炒作)不也刚刚发生么?国内不也出现了年薪200W的工程师牛新庄么?我觉得随着中国IT行业的发展,科技创新将会变得越来越重要,而超级程序员也会越来越成为香饽饽,如果各位同学确实热爱编程,愿意一辈子编程,我希望你坚持下去,因为只要你成为超级程序员肯定会有赏识你的公司。现在的盛大创新院好像做的不错,他们给高级研究员年薪能有30W+,可以算是一个招聘高端人才的例子。而一个反例就是不依靠科技创新的公司(例如团购网站),它们确实是不怎么需要高端人才的,这样的公司不怎么靠技术取胜。

当然,技术不是最重要的,哪怕对Google,对Facebook也是一样。再高端的技术也必须找到市场,满足消费者的需求才能创造财富。我现在相信的是市场>管理>技术。是走管理路线还是走技术路线最好是按照你自己的性格特点来,喜欢干哪个就做哪个,而不是跟风去做管理。只要你努力,做什么都会有回报。

3. 关于英语

关于程序员个人发展,我不得不提及英语能力。我个人感觉,英语是阻碍中国程序员提升眼界的一道非常重要的关卡。关于英语于程序员之重要性,Joe在此书里面说了一句“If you are not good at English you’ll never be a very good programmer.”在欧美IT企业引领科技潮流的今天我们不去学习他们的技术怎么可能追上甚至超越他们?我建议所有有追求的程序员一定要把英语当做最基本的一门编程语言来学习!我自己的亲身经历是:英语帮我打开了另一个更广阔的世界的大门,从此直接阅读原版书酣畅淋漓的学习新知识,从此随意阅读最新的论文了解新动态,从此直接与最厉害的程序员毫无障碍的交流!

4. 创新+创业

我在最近一次Ericsson Research Day上有幸与John Hughes在Demo Session成为邻居,所以才出现了我在推上征求推友关于Erlang问题的一幕。John是从Basic开始学习编程的,在牛津念博士时就做的就是函数式编程的研究,他也是Haskell的创始人之一,95年他来到Chalmers任教至今。他学术上最有影响力的论文之一“QuickCheck: A lightweight Tool for Random Testing of Haskell Programs”成为了他后来创办的Quviq的技术核心。这个公司目前只有四名员工,当然四个人各个都是教授(我知道另一个专做编译器前端的传奇公司EDG也只有5个人)。John为人非常亲切,我跟他聊的非常开心。他追求的编程之美(好吧,我本也不想再用XX之美,但是实在没更合适的词了)是make programming easier — I like my programs to be short, beautiful, and elegant, and I hate drudgery。我还问他你编程是不是有快40年了?他老人家(其实他跟Joe都是精气神特好,非常年轻的那种)想了半天说还真有四十年了。我最羡慕他一点是,他跟我导师Per Stenström一样横跨学术界与工业界,创新与创业双管齐下,互利互惠,既是学识渊博的教授,又是能给社会创造价值的企业家,人生如此,夫复何求?我跟他说真羡慕你真能享受双倍乐趣啊,他说是啊,真是太有趣了!其实中国教授也有在工业界与学术界都取得成功的例子,例如普林斯顿的Li Kai教授和UCSD的Zhou Yuanyuan教授,所以说主要还是环境问题导致的。我个人是龙芯的坚决拥护者,很多人说怎么用MIPS的授权,怎么浪费国家的钱什么什么的,我觉得这些都是扯淡。从我知道的情况来看,龙芯他们组最近把Micro, HPCA, ISCA, ISSCC这些最顶级的会议全发了一个遍,学术水平毫无疑问!胡伟武老师用毛泽东思想来带领团队是有效的(不管是否有失偏薄),而且也有Chen Yunji这样的青年才俊,我相信至少龙芯团队培养出来的这批人才已经足以对社会做出贡献。现在龙芯商业化还处在初期阶段,任重而道远,我祝福他们,看好他们!

中国的发展需要创新!需要最高端的科技人才!需要最顶尖的程序员!

多核的未来

UT Austin的Yale Patt教授上个月来Chalmers交流,做了题为《Future Microprocessors: Multi-core, Mega-nonsense, and What We Must Do Differently Moving Forward》的讲座。Yale Patt是计算机体系结构学术圈的巨擘,他最有名的研究成果是和Branch Predictor和HPS microarchitecture,他的学生们也巨牛无比,学术界有名的有UIUC的Wen-Mei Hwu,CMU的Onur Mutlu等等,工业界Intel不少核心工程师也出自他的门下。这个讲座主要谈了他对未来的多核处理器的发展的看法,有趣的是他二十年前也预测过现在的处理器,我还专门问了他当时的预测是否靠谱,他说“那我得回去查查看才行”,人非常的Nice。

简单介绍一下关键的几点:

1. 为什么要多核?
It is easier than designing a much better uni-core
It is cheaper than designing a much better uni-core
It was embarrassing to continue making L2 bigger
It was the next obvious step

2. Asymmetric Chip Multiprocessor才是未来
一个chip上既有Large Core,又有Small Core,前者专门用来加速那些诸如Critical Section之类的串行代码。

3. ILP未死
其实还有ILP的性能很多可挖掘的空间,只是多核设计上更经济更简单,所以大家都慢慢转到多核上来了

4. Parallel Programming is NOT Hard
如果从新生就开始进行并行编程的教育,从一开始就thinking in parallel,并行编程就不难,关键是打破Abstraction。

UIUC的Distinguished Lecture Series也有他今年4月在UIUC的讲座,甚至还有video。

Enjoy!

多核编程的难题(二)

刚刚过去的一个月一直都在忙着赶实验赶论文,直到前几天完成一篇短论文的写作才得以抽身来补上这一篇关于多核的曙光的文章。我将分几个方面来阐述一下我对多核上并行编程持乐观态度的原因。

1. 较易并行化的应用

如果一个应用的子任务之间依赖关系比较小,相互独立性强,那么它就具有很好的可并行性。很容易我们就会想到服务端的应用。服务端应用的特征就是为多用户提供相似的服务,因为它本身具有内在的并行性,所以相比那些子任务之间依赖性很强的应用来说,它们是比较适合多核的。这些应用常见的例子有大型数据库、飞机票预订系统、银行交易系统、网络搜索、游戏服务器以及云计算所提供的软件即服务(SaaS)等等。

另一种大量采用并行化的成功案例就是图像处理了。举个简单的例子,渲染一幅图像这个任务就充满了大量的数据级并行(data-level parallelism):一幅图像是由许许多多的像素组成的,而现在的GPU都有成百个核心,我们可以比较容易的做到让每个GPU核心分别负责渲染图像的一部分,从而快速的完成整个计算任务。虽然现在来讲GPU上面的编程很难,但是它所能提供的性能提升确实非常可观。

还有很火的GPGPU应用(General-purpost computing on GPU),它们在Scientific Computing领域也有不少成功案例,虽然John Carmack就在Twitter上对GPGPU编程的困难性这样评价过:“Hundreds of GPGPU research papers valiantly struggling with graphic API limitations are painfully obsolete with CUDA / OpenCL available.”其实Scientific Computing可以算是多核上的杀手级应用了,典型的例如天气预测、气候模拟等运用,为了得到更精确的结果肯定就需要处理更多的数据,而且是必须在短时间内出结果,要不然你预测后天的天气但是一个礼拜才给你出结果怎么行?这些大数据量的计算任务对性能的需求永远都是非常大的。而且这些应用本身有很多数据级的并行性,再加上这个领域一般都是行业专家和软件工程师的组合,大规模的应用并行计算是很自然的事情。

2. 我们有持乐观态度的理由

为什么我们可以对多核发展持乐观态度?因为第一点,现在整个工业界、学术界都在研究多核,研究怎样简化并行编程、怎样降低功耗、怎样持续提升性能。Intel和Microsoft资助UIUC和UC Berkeley建立了两个重点实验室,其他顶级研究机构对多核的研究也如火如荼,大量最顶尖的人才都在帮助普及并行计算。第二点,Motivation,即“动机”。免费午餐都结束了,想继续提升性能?你只能进行并行编程。不管是客户端应用也好服务器端应用也好,用户对性能的需求肯定是不会停止的。当并行编程成为持续提升性能的唯一选择时,再困难你也得去做对不对?不过大家不用特别担心,对广大的程序员来讲,一项新技术的普及本身就是需要时间的,现在来讲大量帮助程序员进行并行编程的软硬件工具都在处在发展阶段,我们有理由相信并行编程会更容易更大众。

3. 多核的发展趋势

9月初我去参加斯德哥尔摩举办的Multicore Day时听了一位在Intel负责Nehalem的首席工程师的演讲,里面有几点我记忆深刻:
(1)单核的性能仍在提升
虽然整个工业界主题是往多核发展,但是处理器的单线程性能仍然在持续提升,这是由需求决定的。例如Nehalem架构的i7的单线程性能是奔4的5倍,这一需求也在Google在Micro 2010的论文”Brawny cores still beat wimpy cores, most of the time“中得到印证。这篇文章的核心观点就是性能较弱但是功耗较低的”小号“处理器只有在它们的单核性能接近中档的”大号“处理器时才具有足够的竞争力,否则它们羸弱的单核性能会成为Google现有应用中的性能瓶颈。虽然当初整个业界因为单核性能提升太困难而被迫转向更易实施的多核
(2)CPU和GPU的融合趋势
现在业界已经认同GPU比CPU更适合做数据级并行,而且这类应用需求量很大,这种需求就催生了Intel的Larrabee项目。虽然Larrabee流产了,但是它的技术还在,以后迟早会出现在Intel的产品线上。为了追求更高的性能,GPU和CPU结合的方案会是最好的选择,当然,怎样在这样的硬件上编程又是一个很大的难题。
(3)性能与功耗都重要
Intel的工程师一直在努力确保处理器的性能提升的同时它的功耗也一直在稳步下降。为什么说功耗很重要?我们可以举个很简单的例子,笔记本电脑上运行PowerPoint的速度已经很快了,让PowerPoint运行速度快个一两倍其实并不那么重要,但是如果在保证它运行速度的同时还能让笔记本的续航时间提升一些,这就很有意义了。服务器端更不用说了,现在哪个数据中心不把功耗当做头等大事来考虑?

4. 并行编程的普及教育

虽然说传统的应用一直都以串行计算为背景,所以现在来讲大家普遍觉得并行编程很困难。但是我们换个思路看看:如果从大一开始我们就教新生《并行算法》《并行编程导论》呢?如果程序员一开始就接受的是并行编程的教育,并行编程还是困难的吗?其实我们整个世界本身就充满了并行,人可以同时听课和做笔记,同时吃饭和交流,而计算机硬件更是可以并行工作,为什么软件就不可以?算法导论最新的第三版专门添加了一章《多线程算法》,(该书其中一位作者Prof. Charles Leiserson创办的并行编程的公司Cilk Art也已被Intel收购)让我大胆想象一下,整本算法导论通篇都是“并行”的时代还会远吗?

多核编程的难题(一)

最近David Patterson老爷子(就是计算机体系结构–量化方法的作者之一)发表了一篇文章《The trouble with multicore》,文章高屋建瓴的分析了一下多核发展的当前形势,文章开篇就说了一句话“造芯片的家伙们正忙着生产那些大多数程序员不知道如何编程的多核CPU”。这不由的让我想起我跟我导师Per Stenstrom的一次对话,我问他说“现在多核出来了,有一大堆新的难题等着我们去解决,作为研究人员您是否觉得很兴奋呢?”结果他说“其实我还是有点沮丧的,因为我们是被迫转到多核上来的。”

其实这就道出了多核发展中的一个关键:造硬件的没办法在单核上继续像以前那样容易地提升性能了(有兴趣的朋友可以查下“Power Wall”),为了利用更多的晶体管提高性能,只好走多核这条路,但是在他们选择走这条路的时候,所有人都不知道该如何在多核平台上有效的进行编程,David Patterson管这个叫“Hail Mary”,简单翻译过来就是“让我们多核吧,但是该咋进行多核编程就祈祷奇迹的发生吧!”

好吧,为什么多核编程很困难?一个形象的例子就是把编程比作写书,理论上10个作者同时写一本书应该会比一个人写快10倍。但是他们首先要把任务均匀的分成10份,否则任务最多的那个作者会拖后腿肯定就快不了10倍了。但是呢光这个还不够,如果这个故事中的某一部分必须要在其他部分写完之后才能写,这种顺序上的依赖关系也会拖慢速度;而且10个作者的故事情节还得一致,那么他们肯定少不了沟通啊,这又慢了一点。这就是三个多核编程的最大挑战:“load balancing(负载均衡)”、“sequential dependency(顺序依赖关系)”和“synchronization(同步)”。

难道就没有人尝试着解决这个问题吗?有啊!从60年代开始,一堆一堆的天才们尝试着创造新的编程语言好让并行编程更加美好:APL,Id,Linda,Occam,SISAL等等,他们中有的确实让并行编程更加容易了,但是没有一个人能成功的让他们向传统的串行编程语言一样兼具性能、效率和灵活性,更没有像C/C++、Java这样主要为串行编程设计的语言一样流行。我记得有人问过“Java的并发包挺好用的啊,是不是足够解决多核编程的问题了呢?”,我觉得不然。在语言上进行并行编程的扩展确实是有效的办法,但是它却不能从根本上解决并行编程困难的问题。最根本的原因是这些语言并不是天生为并发而设计的,这就决定了所有的库都只能给你提供并行编程最原始的工具,但是对程序员来说并行编程却并没有因为有了这些库就变得更容易了,你还是得面临死锁dead lock、数据竞跑data race、伪共享false sharing、锁竞争lock contention等种种问题。

讲到这我就想起Erlang了,它就是一种天生为并发设计的语言。它的并发模型核心是基于消息传递机制的轻量级进程,进程之间不共享内存。这样的模型好处就在于每个进程是相互独立的,要通信就发消息好了,最大程度上减少了进程间的依赖关系,从而能提高整体性能,而且核越多跑的越快。但是我们要考虑到Erlang最初是Ericsson为电信系统设计的语言,由它编写的程序的目标就是为了提高系统的throughput以便为更多的用户提供服务,这也是大部分服务器端程序的目标。它们的共同特征是每个用户的请求大部分情况下都是彼此独立的,所以多核对这样的高并发应用来讲其实是有点天生一对的感觉。但是对于传统的客户端程序来讲,latency才是它们的首要目标。例如大型的商业软件,它所希望的是完成一个任务的速度能够更快,或者单位时间内能处理更多的数据。

另一个解决并行编程难的思路就是设计更易进行并行编程的硬件,现在最火的Transactional Memory(事务性内存)就是其中的典范。但是现在它们还只处于研究阶段,里面有一大堆的问题尚待解决,最主要的就是性能还不足以到商用阶段。

还有的人尝试过用编译器自动并行化,但是多年的研究表明纯粹让编译器来给你进行自动并行化是完全走不通了。它能在一定程度上提升程序的性能,但是非常有限,而且随着核数的增加它对性能的提升会更加有限。

那么多核时代的曙光在哪里呢?请看我下一篇文章

第三次软件危机

The major cause of the software crisis is that the machines have become several orders of magnitude more powerful! To put it quite bluntly: as long as there were no machines, programming was no problem at all; when we had a few weak computers, programming became a mild problem, and now we have gigantic computers, programming has become an equally gigantic problem.

造成软件危机的主要原因是因为计算机的计算能力正在呈指数级地增长!说的简单些:在没有计算机的时候,编程根本就不是一个问题;当一些计算能力较弱的计算机出现时,编程成了一个中等难度的问题,而现在,我们拥有了计算能力超绝的计算机,编程就变为了一个同样复杂的问题。

– Edsger Dijkstra, 1972年图灵奖获奖感言

第一次软件危机 (60年代~70年代)

这个时期主要的软件开发方式是使用机器语言或者汇编语言在特定的机器上进行软件的设计与编写。此时的软件规模较小,也不需要使用系统化的软件开发方法,基本上是个人设计编码、个人操作使用的模式。这个时代的程序一个典型特征就是依赖特定的机器,程序员必须根据所使用的计算机的硬件特性编写特定的程序。

然而从60年代中期开始,大容量、高速度计算机问世,程序设计的复杂度也随之增长。1968 年北大西洋公约组织的计算机科学家在联邦德国召开国际会议,第一次讨论软件危机问题,并正式提出“软件工程”一词,从此一门新兴的工程学科——软件工程学——为研究和克服软件危机应运而生,“软件危机”的概念也是在那次会议上由F. L. Bauer提出的。

当时业界最迫切的需求是需要在不损失性能的前提下获得更好的“抽象性”和“可移植性”。此时,比汇编和机器语言更高级的语言相聚诞生,典型的代表莫过于C语言(1972年)。C语言让程序员能让程序员编写的代码在没有或只有较少机器相关性的同时又有不输于汇编语言的性能,而且丰富的语言特性也使得编程难度大大降低,成功的解决了“抽象性”和“可移植性”的问题。

第二次软件危机(80年代~90年代)

这次危机可以归因于软件复杂性的进一步增长。这个时候的大规模软件常常由数百万行代码组成,有数以百计的程序员参与其中,怎样高效、可靠的构造和维护这样规模的软件成为了一个新的难题。著名的《人月神话》中提及,IBM公司开发的OS/360系统共有4000多个模块,约100万条指令,投入5000人年,耗资数亿美元,结果还是延期交付。在交付使用后的系统中仍发现大量(2000个以上)的错误。

这时候人们典型需求的是更好的“可组合性”(Composability)、“可延展性”(Malleability)以及“可维护性”(Maintainability)。程序的性能已经不是一个大问题了,因为摩尔定律能帮你搞定它(70年代编写的C程序仍然能在现在的计算机上运行,而且它还更快!)。为了解决这次危机,面向对象的编程语言(C++、C#、Java等)诞生了,更好的软件工程方法(设计模式、重构、测试、需求分析等等)诞生了,而程序员们也越来越不需要知道硬件是怎么工作的了。软件和硬件的界限越来越牢固,Java编写的代码能在任何JVM支持的平台上运行,程序员也非常乐于享受这样的便利。

第三次软件危机(2005年至今)

兄弟们,“免费的午餐已经结束了”。
摩尔定律在串行机器上宣告失效,多核时代正式来临!

这个时候怎样在多核平台上仍然能保持性能的持续增长就成为了这一次软件危机的核心。并行编程给我们带来了许许多多新的技术难题,现阶段想要高效的利用这些多核平台以获得更好的性能,就必须对计算机的硬件有较深入的理解,而广大程序员却更喜欢能有一些更加便利的编程模型(也许是一门新的语言、也许是新的编程模型)来简单高效地进行并行编程。我们正处在这次危机的开端,前路满是荆棘。但是只要有问题,就会有机会。多核时代,你们的机会在哪里呢?