您的位置:逆风者 新闻资讯 正文
 添加时间:2007-12-23 原文发表:2007-12-23 人气:154

本文章共15576字,分4页,当前第2页,快速翻页:
 

别忘了,至少从上世纪60年代晚期的Simula开始,人们就在写面向对象程序。但到了90年代,面向对象才成功发动革命并夺取统治地位。为什么呢?工业是受现实需求驱动的,为了解决越来越大的问题,必须编写越来越大的系统,这样的系统需要越来越强劲的CPU和存储设备支持,硬件系统也恰逢其时地逐步提供了这样的支持。面向对象编程擅长抽象和依赖管理,所以成为了开发经济、可靠和可重用的大型软件的必备利器。

逆@风@者

并发编程差不多也有同样漫长的历史可以追溯,很早的时候,我们就开始编写协程、管程[译注13]以及其他与并发有关的东西。近10年来,我们也发现有越来越多的程序员在编写并发应用(有多线程的,也有多进程的)系统。但是发生整体转向性的巨变,目前还不具备条件,需假以时日。现有大量的单线程应用,仍然有巨大的存在价值,这点我会在后面说明。

说 点题外话,当前“下一次软件开发革命”这样的词语多如牛毛,让大家眼花缭乱,其实这是商家宣传自己新技术所作的广告,不要理睬它。新技术通常都很吸引人, 有时候也很有用,但软件开发方式的重大变革必然来源于在真正得到爆发式广泛应用前就存在并经过多年缓慢成长、先进而稳定的技术。这个过程是绕不掉的。变革 所依赖的基础技术必须足够成熟(包括有固定的厂商和工具支持);通常,这个成熟稳定过程至少要花费7年的时间,新技术在广泛应用时才不会有潜在的性能悬崖和陷阱。所以,像面向对象这样的软件开发变革,也必须在各项技术经过多年甚至几十年磨砺后才能发生。即便在好莱坞,绝大多数的一夜成名,也仍然是多年努力后发生重大突破的表面象征。

并发将是软件开发史上的又一个重大变革。很多专家仍然在这个变革是否比面向对象还大的问题上争论不休。这样的争论最好还是留给学问家吧。技术工作者最感兴趣的是和面向对象一样,编程方式的变化程度、编程技术的复杂性和学习曲线问题。

 

并发之正反二面

并发技术(特别是多线程)在主流软件里大多应用在两个方面。第一类是天然就彼此独立的、逻辑上分离的控制流程,比如在我设计的数据库复制服务器里,每个复制Session都放在各自的线程里,彼此完全独立的,不会工作于同一条数据记录上。第二类不像第一类那么常见。为了系统提升性能,像利用多CPU平台的能力,挖掘应用程序其他部分的潜能等,我们也会编写并发代码。在我的数据库复制服务器里,多个独立的线程在多CPU平台上就工作得很好。

然而,并发编程也是要付出代价的。一些很明显的问题相对来说无关紧要,比如锁定。对资源的锁定降低了系统的性能,但如果你能找到办法最小化甚至消除资源共享,让操作真正并行,从而明智得当地使用锁,那么从并发执行得到的收益,要远大于在同步上蒙受的损失。

更重要的问题,大概就是并非所有应用都适用并行。这点我会在后面说明。

应该说,最大的问题,就是并发编程本身的难度了。程序员必须将脑子里的编程模型转化为可靠的程序,这比实现顺序执行的传统程序难得多。

任 何学习过并发的人都认为自己已经理解并发,早早结束寻找他们认为不可能但实际潜在的竞争冲突和他们其实仍没闹明白的问题。如果开发人员认真学习和思考并发 编程,就会发现通过合理组织的内部测试能发现大多数的竞争冲突问题,这个时候,无论是在知识水平还是心情愉悦度上,他们都能达到一个新的高度。不过,除了 经过理解为什么和怎么进行真正压力测试的行家测试过的、已经正式发布的软件,都会存在部分在普通测试中无法捕获的潜伏并发问题。这些问题只有在真正的多处 理器系统上才会暴露出来,因为在这样的环境里,多个线程不是在单处理器上切换,而是真正的并发运行,大量新问题就会涌现。而偏偏又有很多人自以为已经真正 理解如何编写并发程序,真是让人忐忑不安啊。我见过不少项目组,他们的程序在很多用户那里即便施以极端苛刻的压力测试,都能出色工作,但某天一个用户部署 了真正的多处理器机器后,深层次的竞争冲突甚至程序崩溃问题马上出现。CPU发 展到今天,重构你的应用,让它们多线程运行在真正的多核计算机上,的确像逼迫初学游泳的人一下子跳入深水——直达终点,似乎有点残忍,但只有真正并行的环 境,才能更容易暴露出你的问题。再说了,即使你组织了一个能真正编写可靠并行代码的团队,也不能说就不会出现问题。例如,并发代码运行可能非常安全,但 (在多核的机子上)却不比在单核的机子上跑得快。其典型原因就是线程未被合理分离,共享了单一资源,造成程序执行顺序化。这类问题是相当微妙而复杂的。

结 构化程序员学习面向对象(什么是对象?什么是虚函数?我如何使用继承?知道“是什么”和“怎么办”外,还得问一句:“如何保证理论上正确的设计在实践中的 正确性?”)是一个飞跃,同样的,顺序思维的程序员学习并发(什么是竞争冲突?什么是死锁?它是怎么出现的,我如何避免它?什么样的构造在我看来是并行的 但实际上顺序化了程序?在“是什么”和“怎么办”外,还要回答同样的问题:“如何保证理论上正确的设计在实践中的正确性?”)也是一个飞跃。

现在的大量程序员并没有真正理解并发,就像15年前大量程序员没有真正理解对象一样。但并发编程模式是可以学习的,尤其是我们要坚持基于消息和锁的编程;一旦真正理解了并发,就会发现它并不比面向对象难多少,很容易觉得那是自然而然的。我们需要为我们自己和我们的团队做好训练投资和时间的准备。

有必要说明一点,我在上面故意将并发编程模式限定在消息和锁基础上。其实也有在语言级就直接支持的无锁编程,比如Java5和很流行的C++编译器。但对于程序员来说,无锁比有锁并发编程难得多。大多数情况下,只需要系统和库编写者理解无锁编程就行了,虽然事实上每个人都可以从无锁系统和库获益。老实说,即便有锁编程,也有点碰运气的味道呢。

 

对我们来说这到底意味着什么

好了,回到正题,将问题归纳一下。

1、我们已经讨论清楚的、最重要结论是:如果应用程序想充分利用CPU吞吐增加量,那它们就必然日益需要并发,这种形势逐渐明朗,并将在接下来的数年里深入发展。Intel已经扬言未来他们会推出集成100颗内核的芯片,那么单线程应用最多就只能利用这种芯片1/100的潜在生产力。“哦,性能没那么重要吧,计算机总是跑得越来越快”的论调已经变得天真而可疑,甚至在未来不久将完全错误。

目 前,并不是所有的应用都需要(或者更准确的说,只有应用中重要的作业才需要)并行。像编译这类的问题,是必须要考虑并行的,而其他则不一定。请看这个有趣 的例子:一个女人需要九个月才能生产一个小孩,并不代表九个女人能花一个月生出一个孩子。你以前可能接触过类似的推导,但有没有感觉这个问题意犹未尽呢? 如果有人再和你就此讨论,我向你推荐一个刁钻的问题:从这个命题你能断定“女人-小孩”是一个非并行问题么?通常,人们会下意识地认为它天然就不是一个并 行问题,但实际上并不完全是这样。如果目的是生一个小孩,它的确是一个非并行问题;但如果是生产多个小孩,那么它就是一个标准的并行问题了!所以说,目标 不同,结论就大相径庭。在考虑你的软件是否和如何使用并行时,千万别忘了面向目标原则。

2、可能不那么明显的结论是:CPU将很可能日益成为应用程序性能的瓶颈。当然,不是所有应用都会这样,目前还未明显受制于CPU能力的应用在未来虽然可能受到CPU影响,CPU也不会一夜之间成为它们的镣铐。但“I/O、网络和数据库瓶颈”似乎快走到谷底,因为在这些领域,条件仍在迅速改善(如GBWiFi网络等等);而与此形成对比的是,CPU性能提升技术已走到峰点。请注意,我们的CPU目前在3GHz徘 徊。所以,除了指望缓存在未来继续扩大(这可真是一个大好消息),现在的单线程应用不太可能跑得更快。其他方面的性能提升手段,虽然未来还可能继续发挥作 用,不过已经无法和过去相提并论了。芯片设计师正在拼命寻找新办法提高管线利用率,降低数据加载延迟,但在这些领域,长在低枝的果子早已被摘光。而应用程 序新需求的增加不但不稍事休息,反而神经质地加速猛冲。我们只好逼迫程序做更多的事情,而程序则只有威逼CPU,压垮它,除非程序能并发执行。

应对如此巨变,我们现在有两条路可以走。一是面向并发重构应用,二是勤俭持家,小心规划代码,让它吃更少的食,干更多的活。这就引出了第三个有趣的话题。

3提升程序效率、优化其性能将越来越重要,而不是反道而行。已经高度重视性能优化的语言将获得重生,其他的语言赶紧奋起直追,朝着效率和优化努力吧。面对长期增长的需求,希望面向性能努力的语言和系统能为我们分忧。

4、最后一点,编程语言和系统将不得不尽快做好面向并发的准备Java语言从一开始就支持并发编程,虽然还存在不少问题以致不得不发布多个后续版本提升并发程序的正确性和效率。C++长期以来被用于编写大型多线程系统,但它却没有对并发的标准支持(ISO C++标准甚至有意未提及线程[译注14] ),因此,并发目前只能在一些不可移植的特定平台和库基础上实现(而且实现还不够完善,比如静态变量只能初始化一次,这就要求编译器自动加锁,但很多C++的实现里并不生成锁)。另外,目前还存在多种并行编程标准,例如pthreadsOpenMP[译注15] , 其中一些支持隐式并行,另一些显式支持。让编译器分析单线程程序并自动生成并行代码的隐式并行方式当然美妙而优雅,不过这类自动转化工具的结果代码质量还 无法与人工编写的显式并行代码媲美。目前的并发编程主要以锁为基础,这种方式也很难把握,常常要赌几分运气。总之,我们迫切需要一个比目前语言提供的更高 抽象层次的、统一的并发编程模式。关于这点,以后我还有更多的话要说。

 

总结

如果你以前对并发未加注意,那么现在是时候了,仔细分析应用的设计,挑出现在和不久就可能过于依赖CPU能力的操作,研究这些部分如何从并发得益。你和你的团队,现在也该深入学习和了解并发编程的要求、不足、风格和专业概念了。

少部分应用天然适用于并行,但大多数不是的。即便你知道程序受制于CPU的位置,可能也很难找到将这部分操作并行化的办法。所有这些问题,要求我们加快对并行的思考和研究。隐式并行编译器能帮点小忙,但不能指望太多,它不可能比得上尽你所能将顺序化程序转化为显式并行和多线程版本后的效果的。

感 谢仍未停止的缓存扩大和管线少量优化,免费饭菜在今后还能有一点,不过从今天开始,餐馆无偿提供的只有小菜和饭后小点心了。菜谱上仍然有优质可口的鱼片, 但现在要享受它就得付费——设计精细化、代码更复杂,而且要加倍测试。对于多数应用来说,这是个好消息,尽管要辛勤耕耘,但回报是丰厚的,因为并发可以让 应用继续从处理器能力暴增中充分受益。

 

 

译注1

处理器发展历史上,精简指令集(RISCReduced Instruction Set Computer)阵营曾向微特尔(WintelMicrosoftIntel)阵营发动过三波声势浩大的微电脑盟主争霸战。

上世纪70年代以来,对处理器的要求更为全面,不单是提升速度就能满足,比如低耗能、小体积,加强数值运算、支持多媒体功能等。复杂指令集(CISCComplex Reduced Instruction Set Computer)的微指令多且长度不统一,造成解码器线路复杂;加上受当时制造工艺的限制,如果在芯片上直接集成高速缓存和其他部件,体积和价格都将变得难以想象。

RISC应运而生。因为RISC指令精简、线路精简,所以芯片体积和能耗降低,腾出空间也可容纳更多寄存器;另外指令定长,通过硬件加速,还可提升效能。RISC学术界从一开始就分为两派:Berkeley RISC(伯克利大学RISC计划)和Stanford MIPS(斯坦福大学MIPS计划。MIPSMicroprocessor without Interlocked Pipeline Stages,无内部互锁流水级的微处理器。我国龙芯即MIPS架构)。

Sun公司引进了RISC技术,在此基础上制定了SparcScalable Processor Architecture,可扩展处理器体系结构)微处理器体系结构规范,并于1985年推出了相应处理器。1988年,Sun领头组建了Sparc联盟,口号是“RISC + UNIX vs CISC + DOS”,藉此发动第一次争霸冲击。后因市场迟迟未见销量,加上Sun在技术上又留了一手,导致联盟最后只剩Sun自己和德州仪器。

1990年,MIPS研究开花结果,开发团队成立了同名公司MIPS,并于1991年建立了ACEAdvanced Computing Environment)联盟,主要成员有Digital(迪吉多)、SGISilicon Graphics,视算科技)和Compaq(康柏)。Compaq当时市场低迷,且IntelCompaq展开了游说,因此Compaq最先退出了联盟;而Digital又忙于Alpha芯片的开发。主要成员离心离德,1992年,第二次联盟以SGI收购MIPS草草收场。

IBM1975
 

本文章更多内容<<上一页 - 1 - 2 - 3 - 4 - 下一页>>
相关文章

SQL Server 2008综合数据可编程性
微软推出房屋3D模型制作工具:Virtual Eart
计算机时代的战争——黑客游戏
“我心飞扬”易语言编程大奖赛开始了
一等奖选手免试读北大清华
深入浅出:Java设计模式之适配器模式
专家看台:真正的程序员天生爱数学
在PHPX对于 类 问题的回帖
微软将在Visual Studio开发平台中整合F#语言
个人网页中必不可少的十五大Web API
微软公司2008新技术预览
易语言4.06正式版发布

相关评论


本文章所属分类:首页 新闻资讯

  热门关键字: