<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>冒号空间 &#187; 进程</title>
	<atom:link href="http://blog.zhenghui.org/tag/process/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.zhenghui.org</link>
	<description>自然、人类、机器</description>
	<lastBuildDate>Fri, 16 Jul 2010 18:33:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>冒号课堂§2.4：并发范式</title>
		<link>http://blog.zhenghui.org/2009/09/07/colon-class-2_4/</link>
		<comments>http://blog.zhenghui.org/2009/09/07/colon-class-2_4/#comments</comments>
		<pubDate>Mon, 07 Sep 2009 05:14:57 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[函数式编程]]></category>
		<category><![CDATA[对象式编程]]></category>
		<category><![CDATA[并发式编程]]></category>
		<category><![CDATA[线程]]></category>
		<category><![CDATA[编程范式]]></category>
		<category><![CDATA[过程式编程]]></category>
		<category><![CDATA[进程]]></category>
		<category><![CDATA[逻辑式编程]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=361</guid>
		<description><![CDATA[<b>并发范式</b>——合作与竞争（<em>并发式编程简谈</em>）<br/>
•	有谁愿意驾驶一辆启动后不能刹车、不能倒车、不能变速、油尽方停的汽车呢？<br/>
•	并发式编程以进程为导向、以任务为中心将系统模块化<br/>
•	并发式编程以资源共享与竞争为主线]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体">第二课 重要范式(4)</span></strong>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="并发范式"><div class="titlepage"><div><div><h1 class="title"><a name="id599705"></a>2.4 并发范式——合作与竞争</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>并发式编程简谈</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>在合作中竞争，在竞争中合作</p></div><div class="attribution"><span>—<span class="attribution">《竞合》</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    有谁愿意驾驶一辆启动后不能刹车、不能倒车、不能变速、油尽方停的汽车呢？
                </p></li><li class="listitem"><p>
                    并发式编程以进程为导向、以任务为中心将系统模块化
                </p></li><li class="listitem"><p>
                    并发式编程以资源共享与竞争为主线
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>并发式编程有何特点？</p></li><li class="listitem"><p>并发式编程有哪些好处？</p></li><li class="listitem"><p>合理的并发式编程设计应满足哪些条件？ </p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            逗号好奇地问：“还有其他类型的编程范式吗？”
        </p><p>
            “不但有，而且有很多。”冒号喝了一口水，悠悠地说，“<span class="term">并发式编程</span>（concurrent programming）就是其中之一。”
        </p><p>
            叹号有些惊讶：“并发式编程也算一种范式？它似乎更像是提高运行效率的一种手段。” 
        </p><p>
            “大谬不然。”冒号摇摇头，“真正的并发式编程，绝不只是调用线程<a class="link" href="#note1"><sup>[1]</sup></a>API或使用synchronized、lock之类的关键字那么简单。从宏观的架构设计，到微观的数据结构、流程控制乃至算法，相比通常的串行式编程都可能发生变化。随着硬件性能和用户需求的双重提升，并发式编程已成为不可回避的主题。毫不夸张地说，并发式编程是继OOP之后又一场思想和技术上的革命。只是相比OOP，尽管年龄相仿，但语言上不够支持，标准上不够统一，理论上不够完善，因而这场革命更具<span class="emphasis"><em>破坏性</em></span>和<span class="emphasis"><em>建设性</em></span>。现在我们来看一个例子，比较两种烧水泡茶的方案。”
        </p><p>
            说着冒号在黑板上写下——
        </p><div class="informalexample"><p>方案一：洗茶杯；放茶叶；灌水壶；烧水；水开后泡茶。</p><p>方案二：灌水壶；在烧水的同时，洗茶杯；放茶叶；水开后泡茶。</p></div><p>
            引号见多识广：“我记得这好像是运筹学中的例子，显然方案二更佳。从编程的角度来看，方案一是串行式编程，方案二是并发式编程——烧水的线程与洗茶杯放茶叶的线程是同时进行的。”
        </p><p>
            “如果方案一也用并发式编程呢？”冒号追问。
        </p><p>
            引号一愣，随即道：“必须先洗茶杯后放茶叶，洗茶杯放茶叶的同时也没法烧水，至于泡茶，更得等水开之后了。”
        </p><p>
            句号明白了冒号的用意：“这就是说，单凭并发式编程并不能保证提高程序性能，还必须在程序设计上下功夫。” 
        </p><p>
            问号继续深究：“即便如此，如果硬件不支持，并发式编程也未必能提高效率啊。比如在一台单处理器的主机上，多个线程只能是模拟的、逻辑上的并行，而非真正物理上的并行。”
        </p><p>
            “这话有一定道理。”冒号有限度地表示赞同，“但设计者应该未雨绸缪，总不能等到有了多处理器才想到并发式编程吧？再者，没有多处理器，是不是可以利用多台单处理器的主机同时运算呢？退一步讲，即使在一台单处理器的情况下，并发式编程有时也是必不可少的。它能保证不同用户、不同程序之间的公平竞争，这对多用户、多任务的系统而言尤为重要。此外，采用并发式编程同样可能提高性能。最典型的一个例子：当一个线程因为等待某种资源而被堵塞时，可以切换到其他线程而不至让CPU闲置。更重要的一点是，难道除了缩短程序运行时间外，并发式编程就没有别的好处吗？譬如打开一个网页，你是希望浏览器边下载边显示网页呢，还是下载完成后再显示？”
        </p><p>
            “当然是边下载边显示啦。” 叹号毫不犹豫地说，“如果每个网页都是下载完成后再显示，那还不把人给憋坏了！”
        </p><p>
            逗号加了一句：“浏览器加载文字和加载图像也应分开在不同的线程，如果用户对文字部分不感兴趣，不等图像显示就可直接关闭网页了。”
        </p><p>
            “如果网页被提前关闭，那也是假用户之手变相缩短了程序运行时间。”冒号接过话来，“还有一个常见的例子，包括浏览器在内的许多应用软件在运行中都会显示一个进程条。该进程条的更新需要一个单独的线程，从效率上看它起的作用是负面的，但大大提高了用户体验，是软件人性化的表现。再举一例，媒体播放器一般都会提供暂停、快进、倒退、快放、慢放等按钮，如果不采用多线程，它们将形同虚设。此处并发式编程的作用在于提高了软件的响应能力，也改善了用户体验——有谁愿意驾驶一辆启动后不能刹车、不能倒车、不能变速、油尽方停的汽车呢？”
        </p><p>
            “岂止是不愿意，简直是恐怖！”叹号加重了语气。
        </p><p>
            “对于操作系统、各种实时系统和诸如数据库、网络服务器等基于服务的系统来说，在响应用户请求的时间上和资源的合理分配上有着极高的要求，并发式编程更是不可或缺。”句号接着补充。
        </p><p>
            问号紧接着又问：“并发式编程还有其他用处吗？”
        </p><p>
            冒号应道：“不同编程范式采用不同的视角和方法来设计和开发软件。并发式编程<span class="emphasis"><em>以进程为导向</em></span>（Process-Oriented）、以任务为中心将系统模块化。我们都知道，模块化在编程中是个好东西。”
        </p><p>
            引号心存疑惑：“过程式中引入了函数模块，对象式中引入了对象模块，但并发式似乎没有<span class="emphasis"><em>在语法上</em></span>引入新型模块，比如C和Java中的线程其实不过是函数或方法的包装而已。”
        </p><p>
            “我猜你的意思是：在定义一个线程之前，其主函数已经模块化了，不能把功劳记在并发式编程上，对吧？”冒号笑问，“你不能孤立静止地看待每个模块，还要考虑到模块之间的相互关联和作用。相比串行式，并发式在模块之间引入了新的通讯和控制方式。也就是说，原先的一些模块的定义和划分一定是建立在线程机制的基础上的。如果失去线程的支持，它们的合理性自然会打上问号，说不定整体设计都会受到牵连。这也体现了编程范式的<span class="emphasis"><em>渗透性和全局影响力</em></span>。”
        </p><p>
            教室上空弥漫的疑云一消而散。
        </p><p>
            冒号进一步指出：“除了用户主观上的需求和硬件客观上的可能外，并发式显得格外重要的另一深层原因是：许多程序是现实世界的模拟，而我们生活的世界不折不扣是并发式的。从某种意义上看，并发式的模拟比对象式的模拟更贴近世界。”
        </p><p>
            引号再次提问：“并发式编程在设计上有什么要求？”
        </p><p>
            “并发式编程<span class="strong"><strong>以资源共享与竞争为主线</strong></span>——又是对当今世界形势的一个逼真模拟。这意味着程序设计将围绕进程的划分与调度、进程之间的通讯与同步<a class="link" href="#note2"><sup>[2]</sup></a>等等来展开。合理的并发式设计需要诸多方面的权衡考量。”冒号说着，放出一段幻灯片——
        </p><div class="informalexample"><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>软件易于重用、维护、测试</p></li><li class="listitem"><p>公平有效地利用资源，优化程序性能如增大吞吐量、减少响应时间、提高效率等</p></li><li class="listitem"><p>保障进程安全，防止<span class="term">竞态条件</span>（race condition）</p></li><li class="listitem"><p>保持进程活性，避免死锁、饥饿、活锁、资源枯竭等</p></li><li class="listitem"><p>减少锁开销、上下文切换等带来的性能损失</p></li><li class="listitem"><p>妥善处理多进程在算法、调试等方面带来的复杂性</p></li></ul></div></div><p>
            叹号蹙眉：“并发式编程好是好，就是太复杂。”
        </p><p>
            “天下没有免费的午餐。有所得，必有所失。” 冒号淡淡地说，“并发式编程当然不容易，但也并非难以掌握。最重要的是，作为一个程序员，你不得不面对它。即使你不直接用并发式编程，你依赖的代码和依赖你的代码也可能用到；即使现在没有用并发式，将来也可能用到。如果采取避而不理的鸵鸟政策，早晚会被人点中你的死穴。虽然目前不会对并发式编程作更深入的探讨，但希望能引起你们足够的重视。”
        </p><p>
            句号谈及他的感受：“相比OOP在语言上得到的支持，并发式的支持力度好像很不够。”
        </p><p>
            冒号点头称是：“这是由并发式的复杂性和成熟度决定的。另外，在究竟是在语言级别上支持并发、还是交由操作系统处理的问题上，仁者见仁，智者见智。Ada、Java和C#等选择前者，在语法上对并发式编程有一定的支持；C和C++等选择后者，除了关键字volatile外，主要靠库函数支持。专门为并发式而设计的语言大多仅限于学术研究而非商业应用，Erlang语言<a class="link" href="#note3"><sup>[3]</sup></a>是少数的例外。顺带提一下，前面提到的声明式语言具有无副作用的特性，尤其适合于并发式编程。”
        </p><p>
            问号提了一个听似奇怪的问题：“并发式与前面提到的对象式有无共通之处？”
        </p><p>
            “并发式与对象式虽是互相正交的两种范式，倒真有些相通呢。”冒号回答，“它们均与三大核心范式正交，并且越来越广泛地向它们渗透着；均为传统编程的一种推广——并发式进程的个数为一时即为传统的串行式编程，对象的方法个数为为零即为传统的数据类型；均将整个程序系统分解为<span class="emphasis"><em>若干独立的子系统</em></span>，不同的是一个以<span class="emphasis"><em>任务</em></span>为单位，一个以<span class="emphasis"><em>对象</em></span>为单位；子系统之间均能交流与合作，不同的是一个以<span class="emphasis"><em>竞争</em></span>为主题，一个以<span class="emphasis"><em>服务</em></span>为主题。如果将程序系统视作公司，那么并发式系统是<span class="emphasis"><em>产品型</em></span>公司，每个进程是一名工人，其职责是执行<span class="emphasis"><em>单一</em></span>任务；对象式系统是<span class="emphasis"><em>服务型</em></span>公司，每个对象是一名服务员，其职责是提供<span class="emphasis"><em>系列</em></span>服务。由此可见，一名优秀的程序设计师也应该是一名优秀的管理者。”
        </p><p>
            句号提出：“迄今为止我们谈到了五种范式，能否对它们简单概括一下？”
        </p><p>
            “你提问的时机把握得不错嘛。”冒号开始如数家珍，“为便于记忆，我们不妨用‘一二三四五’来概括编程范式之最：最传统的<span class="emphasis"><em>一个</em></span>是命令式；最基本的<span class="emphasis"><em>两个</em></span>是命令式和声明式；最核心的<span class="emphasis"><em>三个是</em></span>命令式、函数式和逻辑式；最主要的<span class="emphasis"><em>四个</em></span>是命令式、函数式、逻辑式和对象式；最重要的<span class="emphasis"><em>五个</em></span>是命令式、函数式、逻辑式、对象式和并发式。最后，我们来对比一下五大范式。”
        </p><p>
            少顷，黑板上出现几行排比句——
        </p><div class="informalexample"><p>过程式：以过程为模块的君主体系，模块之间互相授命与听命</p><p>函数式：以函数为模块的数学体系，模块之间互相替换与合成</p><p>逻辑式：以断言为模块的逻辑体系，模块之间互相归纳与演绎</p><p>对象式：以对象为模块的民主体系，模块之间互相交流与服务</p><p>并发式：以进程为模块的生产体系，模块之间互相竞争与合作</p></div><p>
            “说回并发式编程，它要求我们摆脱以往习惯的按部就班的思维方式，对编程提出了更高的挑战。程序世界与现实世界一样，呈百舸争流、千帆竞发之势，不进则退啊！”言讫，冒号宣布，“第二堂课到此为止，欢迎下次光临。” 
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    并发式编程中以进程（process）或线程（thread）为基本单位。尽管它们有很大的差异，但为简明起见，这里不加区分地交替使用两个术语。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    <span class="term">同步</span>（synchronization）只在采用<span class="term">共享内存</span>（shared memory）的并发模型中需要，在采用<span class="term">消息传递</span>（message passing）的并发模型中并不需要。本文主要以前一种并发模型为讨论对象，它也是大多数语言或库（包括C、C++、Java、C#等）所支持的模型。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    Erlang是由爱立信开发的一种通用编程语言，支持函数式和并发式，采用消息传递的并发模型。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    并发式编程以进程为导向、以任务为中心、以资源共享与竞争为主线。
                </p></li><li class="listitem"><p>
                    并发式编程有助于提高运行效率、充分利用资源、提高软件的响应能力、改善用户体验、保证公平竞争，同时以进程为单位将系统模块化，更加真实地模拟现实世界。
                </p></li><li class="listitem"><p>
                    合理的并发式设计应该做到：软件易于重用、维护和测试；有效地利用资源，优化程序性能；保障进程安全和活性；减少性能损失和复杂度。
                </p></li><li class="listitem"><p>
                    对象式和并发式在传统编程的基础上，分别从不同的方向进行拓展：对象式在数据类型上进行推广——允许运算作为数据类型的成员；并发式在执行顺序上进行推广——允许不同运算的执行在时间上交替或者重合。它们与三大核心范式一道，组成了最重要的五大编程范式。
                </p></li><li class="listitem"><div class="table"><a name="id640460"></a><p class="title">五大重要范式对比：</p><div class="table-contents"><table summary="五大重要范式对比" border="1"><colgroup><col><col><col><col></colgroup><thead><tr><th>范式</th><th>体系</th><th>模块</th><th>模块关系</th></tr></thead><tbody><tr><td>过程式</td><td>君主体系</td><td>过程</td><td>授命与听命</td></tr><tr><td>函数式</td><td>数学体系</td><td>函数</td><td>替换与合成</td></tr><tr><td>逻辑式</td><td>逻辑体系</td><td>断言</td><td>归纳与演绎</td></tr><tr><td>对象式</td><td>民主体系</td><td>对象</td><td>交流与服务</td></tr><tr><td>并发式</td><td>生产体系</td><td>进程</td><td>竞争与合作</td></tr></tbody></table></div></div><br class="table-break"></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Abraham Silberschatz，Peter Galvin．Operating System Concepts，5ed.．Reading, MA：Addison-Wesley，1998．155-235
                </p></li></ol></div></div></div>

<!-- below is edited manually -->
<strong><span style="font-family: 宋体">课后思考</span></strong>
<ul style="margin-top: 0cm; list-style-type: none">
    <li>02-01 在你所掌握的语言当中，有哪些是命令式的？哪些是声明式的？其中，命令式语言里有哪些声明式的特征？声明式的语言里有哪些命令式的特征？它们各自有哪些优点和缺点？</li>
    <li>02-02 你编写的程序符合结构化编程的原则吗？</li>
    <li>02-03 你接触过函数式语言和逻辑式语言吗？如果没有，试着阅读相关的入门书籍，体会它们与过程式迥然不同的风味。（函数式语言推荐Haskell和 Scheme，逻辑式语言推荐Prolog）</li>
    <li>02-04 相比纯过程式的编程语言（如C语言），你认为OOP语言主要有哪些优势？又有哪些劣势？</li>
    <li>02-05 你认为在并发式编程设计中，最重要的是什么？最困难的是什么？</li>
</ul><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F07%2Fcolon-class-2_4%2F&amp;linkname=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A72.4%EF%BC%9A%E5%B9%B6%E5%8F%91%E8%8C%83%E5%BC%8F">分享/保存</a>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/07/colon-class-2_4/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
