第二课 重要范式(4)html
2.4并发范式——合做与竞争程序员
在合做中竞争,在竞争中合做 ——《竞合》算法
关键词:编程范式,并发式编程,线程,进程,过程式编程,函数式编程,逻辑式编程,对象式编程数据库
摘要:并发式编程简谈编程
!预览浏览器
· 有谁愿意驾驶一辆启动后不能刹车、不能倒车、不能变速、油尽方停的汽车呢?安全
· 并发式编程以进程为导向、以任务为中心将系统模块化服务器
· 并发式编程以资源共享与竞争为主线网络
?提问数据结构
:讲解
逗号好奇地问:“还有其余类型的编程范式吗?”
“不但有,并且有不少。”冒号喝了一口水,悠悠地说,“并发式编程(concurrent programming)就是其中之一。”
叹号有些惊讶:“并发式编程也算一种范式?它彷佛更像是提供运行效率的一种手段。 ”
“大谬否则。”冒号摇摇头,“真正的并发式编程,毫不只是调用线程[1]API或使用synchronized、lock之类的关键字那么简单。从宏观的架构设计,到微观的数据结构、流程控制乃至算法,相比一般的串行式编程均可能发生变化。随着硬件性能和用户需求的双重提高,并发式编程已成为不可回避的主题。绝不夸张地说,并发式编程是继OOP以后又一场思想和技术上的革命。只是相比OOP,尽管年龄相仿,但语言上不够支持,标准上不够统一,理论上不够完善,于是这场革命更具破坏性和建设性。如今咱们来看一个例子,比较两种烧水泡茶的方案。”
说着冒号在黑板上写下——
方案一:洗茶杯;放茶叶;灌水壶;烧水;水开后泡茶。
方案二:灌水壶;在烧水的同时,洗茶杯;放茶叶;水开后泡茶。
引号见多识广:“我记得这好像是运筹学中的例子,显然方案二更佳。从编程的角度来看,方案一是串行式编程,方案二是并发式编程——烧水的线程与洗茶杯放茶叶的线程是同时进行的。”
“若是方案一也用并发式编程呢?”冒号追问。
引号一愣,随即道:“必须先洗茶杯后放茶叶,洗茶杯放茶叶的同时也无法烧水,至于泡茶,更得等水开以后了。 ”
句号明白了冒号的用意:“这就是说,单凭并发式编程并不能保证提升程序性能,还必须在程序设计上下功夫。”
问号继续深究:“即使如此,若是硬件不支持,并发式编程也未必能提升效率啊。好比在一台单处理器的主机上,多个线程只能是模拟的、逻辑上的并行,而非真正物理上的并行。”
“这话有必定道理。”冒号有限度地表示赞同,“但设计者应该未雨绸缪,总不能等到有了多处理器才想到并发式编程吧?再者,没有多处理器,是否是能够利用多台单处理器的主机同时运算呢?退一步讲,即便在一台单处理器的状况下,并发式编程也是必不可少的。它能保证不一样用户、不一样程序之间的公平竞争,这对多用户、多任务的系统而言尤其重要。此外,采用并发式编程一样可能提升性能。最典型的一个例子:当一个线程由于等待某种资源而被堵塞时,能够切换到其余线程而不至让CPU闲置。更重要的一点是,难道除了缩短程序运行时间外,并发式编程就没有别的好处吗?譬如打开一个网页,你是但愿浏览器边下载边显示网页呢,仍是下载完成后再显示?”
“固然是边下载边显示啦。” 叹号绝不犹豫地说,“若是每一个网页都是下载完成后再显示,那还不把人给憋坏了!”
逗号加了一句:“浏览器加载文字和加载图像也应分开在不一样的线程,若是用户对文字部分不感兴趣,不等图像显示就可直接关闭网页了。 ”
“若是网页被提早关闭,那也是假用户之手变相缩短了程序运行时间。”冒号接过话来,“还有一个常见的例子,包括浏览器在内的许多应用软件在运行中都会显示一个进程条。该进程条的更新须要一个单独的线程,从效率上看它起的做用是负面的,但大大提升了用户体验,是软件人性化的表现。再举一例,媒体播放器通常都会提供暂停、快进、倒退、快放、慢放等按钮,若是不采用多线程,它们将形同虚设。此处并发式编程的做用在于提升了软件的响应能力,也改善了用户体验——有谁愿意驾驶一辆启动后不能刹车、不能倒车、不能变速、油尽方停的汽车呢?”
“岂止是不肯意,简直是恐怖!”叹号加剧了语气。
“对于操做系统、各类实时系统和诸如数据库、网络服务器等基于服务的系统来讲,在响应用户请求的时间上和资源的合理分配上有着极高的要求,并发式编程更是不可或缺。”句号接着补充。
问号随即又问:“并发式编程还有其余用处吗?”
冒号应道:“不一样编程范式采用不一样的视角和方法来设计和开发软件。并发式编程以进程为导向 (Process-Oriented)、以任务为中心将系统模块化。咱们都知道,模块化在编程中是个好东西。”
引号心存疑惑:“过程式中引入了函数模块,对象式中引入了对象模块,但并发式彷佛没有在语法上引入新型模块,好比C和Java中的线程其实不过是函数或方法的包装而已。”
“我猜你的意思是:在定义一个线程以前,其主函数已经模块化了,不能把功劳记在并发式编程上,对吧?”冒号笑问,“你不能孤立静止地看待每一个模块,还要考虑到模块之间的相互关联和做用。相比串行式,并发式在模块之间引入了新的通信和控制方式。也就是说,原先的一些模块的定义和划分必定是创建在线程机制的基础上的。若是失去线程的支持,它们的合理性天然会打上问号,说不定总体设计都会受到牵连。这也体现了编程范式的渗透性和全局影响力。”
教室上空弥漫的疑云一消而散。
冒号进一步指出:“除了用户主观上的需求和硬件客观上的可能外,并发式显得格外重要的另外一深层缘由是:许多程序是现实世界的模拟,而咱们生活的世界彻彻底底是并发式的。从某种意义上看,并发式的模拟比对象式的模拟更贴近世界。”
引号再次提问:“并发式编程在设计上有什么要求?”
“并发式编程以资源共享与竞争为主线——又是对当今世界形势的一个逼真模拟。这意味着程序设计将围绕进程的划分与调度、进程之间的通信与同步[2]等等来展开。合理的并发式设计须要诸多方面的权衡考量。”冒号说着,放出一段幻灯片——
叹号蹙眉:“并发式编程好是好,就是太复杂。”
“天下没有免费的午饭。有所得,必有所失。” 冒号淡淡地说,“并发式编程固然不容易,但也并不是难以掌握。最重要的是,做为一个程序员,你不得不面对它。即便你不直接用并发式编程,你依赖的代码和依赖你的代码也可能用到;即便如今没有用并发式,未来也可能用到。若是采起避而不理的鸵鸟政策,迟早会被人点中你的死穴。虽然目前不会对并发式编程做更深刻的探讨,但但愿能引发大家足够的重视。”
句号谈及他的感觉:“相比OOP在语言上获得的支持,并发式的支持力度好像很不够。”
冒号点头称是:“这是由并发式的复杂性和成熟度决定的。另外,在到底是在语言级别上支持并发、仍是交由操做系统处理的问题上,仁者见仁,智者见智。Ada、Java和C#等选择前者,在语法上对并发式编程有必定的支持;C和C++等选择后者,除了关键字volatile外,主要靠库函数支持。专门为并发式而设计的语言大多仅限于学术研究而非商业应用,Erlang语言[3]是少数的例外。顺带提一下,前面提到的声明式语言具备无反作用的特性,尤为适合于并发式编程。”
问号提了一个听似奇怪的问题:“并发式与前面提到的对象式有无共通之处?”
“并发式与对象式虽是互相正交的两种范式,倒真有些相通呢。”冒号回答,“它们均与三大核心范式正交,而且愈来愈普遍地向它们渗透着;均为传统编程的一种推广——并发式进程的个数为一时即为传统的串行式编程,对象的方法个数为为零即为传统的数据类型;均将整个程序系统分解为若干独立的子系统,不一样的是一个以任务为单位,一个以对象为单位;子系统之间均能交流与合做,不一样的是一个以竞争为主题,一个以服务为主题。若是将程序系统视做公司,那么并发式系统是产品型公司,每一个进程是一名工人,其职责是执行单一任务;对象式系统是服务型公司,每一个对象是一名服务员,其职责是提供系列服务。因而可知,一名优秀的程序设计师也应该是一名优秀的管理者。”
句号提出:“迄今为止咱们谈到了五种范式,可否对它们简单归纳一下?”
“你提问的时机把握得不错嘛。”冒号开始如数家珍,“为便于记忆,咱们不妨用‘一二三四五’来归纳编程范式之最:最传统的一个是命令式;最基本的两个是命令式和声明式;最核心的三个是命令式、函数式和逻辑式;最主要的四个是命令式、函数式、逻辑式和对象式;最重要的五个是命令式、函数式、逻辑式、对象式和并发式。最后,咱们来对比一下五大范式。”
少顷,黑板上出现几行排比句——
过程式:以过程为模块的君主体系,模块之间互相授命与听命
函数式:以函数为模块的数学体系,模块之间互相替换与合成
逻辑式:以断言为模块的逻辑体系,模块之间互相概括与演绎
对象式:以对象为模块的民主体系,模块之间互相交流与服务
并发式:以进程为模块的生产体系,模块之间互相竞争与合做
“说回并发式编程,它要求咱们摆脱以往习惯的循序渐进的思惟方式,对编程提出了更高的挑战。程序世界与现实世界同样,呈百舸争流、千帆竞发之势,不进则退啊!”言讫,冒号宣布,“第二堂课到此为止,欢迎下次光临。”
,插语
[1] 并发式编程中以进程(process)或线程(thread)为基本单位。尽管它们有很大的差别,但为简明起见,这里不加区分地交替使用两个术语。
[2] 同步(synchronization)只在采用共享内存(shared memory)的并发模型中须要,在采用消息传递(message passing)的并发模型中并不须要。本文主要之前一种并发模型为讨论对象,它也是大多数语言或库(包括C、C++、Java、C#等)所支持的模型。
[3] Erlang是由爱立信开发的一种通用编程语言,支持函数式和并发式,采用消息传递的并发模型。
。总结
· 并发式编程以进程为导向、以任务为中心、以资源共享与竞争为主线。
· 并发式编程有助于提升运行效率、充分利用资源、提升软件的响应能力、改善用户体验、保证公平竞争,同时以进程为单位将系统模块化,更加真实地模拟现实世界。
· 合理的并发式设计应该作到:软件易于重用、维护和测试;有效地利用资源,优化程序性能;保障进程安全和活性;减小性能损失和复杂度。
· 对象式和并发式在传统编程的基础上,分别从不一样的方向进行拓展:对象式在数据类型上进行推广——容许运算做为数据类型的成员;并发式在执行顺序上进行推广——容许不一样运算的执行在时间上交替或者重合。它们与三大核心范式一道,组成了最重要的五大编程范式。
· 五大重要范式对比:
范式 |
体系 |
模块 |
模块关系 |
过程式 |
君主体系 |
过程 |
授命与听命 |
函数式 |
数学体系 |
函数 |
替换与合成 |
逻辑式 |
逻辑体系 |
断言 |
概括与演绎 |
对象式 |
民主体系 |
对象 |
交流与服务 |
并发式 |
生产体系 |
进程 |
竞争与合做 |
“”参考
[1] Abraham Silberschatz,Peter Galvin.Operating System Concepts,5ed..Reading, MA:Addison-Wesley,1998.155-235
课后思考
· 在你所掌握的语言当中,有哪些是命令式的?哪些是声明式的?其中,命令式语言里有哪些声明式的特征?声明式的语言里有哪些命令式的特征?它们各自有哪些优势和缺点?
· 你编写的程序符合结构化编程的原则吗?
· 你接触过函数式语言和逻辑式语言吗?若是没有,试着阅读相关的入门书籍,体会它们与过程式迥然不一样的风味。(函数式语言推荐Haskell和 Scheme,逻辑式语言推荐Prolog)
· 相比纯过程式的编程语言(如C语言),你认为OOP语言主要有哪些优点?又有哪些劣势?
· 你认为在并发式编程设计中,最重要的是什么?最困难的是什么?
http://www.cnblogs.com/xyz98/archive/2009/03/29/1424666.html