﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-庄周梦蝶-随笔分类-erlang</title><link>http://www.blogjava.net/killme2008/category/20770.html</link><description>天行健，君子以自强不息</description><language>zh-cn</language><lastBuildDate>Tue, 13 Apr 2010 11:17:26 GMT</lastBuildDate><pubDate>Tue, 13 Apr 2010 11:17:26 GMT</pubDate><ttl>60</ttl><item><title>Ruby Fiber指南（五）： 实现Actor，兼谈Erlang的process调度</title><link>http://www.blogjava.net/killme2008/archive/2010/04/13/318182.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 13 Apr 2010 10:31:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/04/13/318182.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/318182.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/04/13/318182.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/318182.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/318182.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; <br />
&nbsp; &nbsp; <a href="/killme2008/archive/2010/03/11/315158.html">Ruby Fiber指南（一）基础</a><br />
&nbsp;&nbsp;&nbsp; <a href="/killme2008/archive/2010/03/11/315197.html">Ruby Fiber指南（二）参数传递</a><br />
&nbsp;&nbsp;&nbsp; <a href="/killme2008/archive/2010/03/11/315215.html">Ruby Fiber指南（三）过滤器</a><br />
&nbsp;&nbsp;&nbsp;<a href="/killme2008/archive/2010/03/12/315257.html"> Ruby Fiber指南（四）迭代器</a><br />
&nbsp;&nbsp;&nbsp; <a title="Ruby Actor指南（五）实现Actor" href="http://www.blogjava.net/killme2008/archive/2010/04/13/318182.html">Ruby Actor指南（五）实现Actor</a><br />
<br />
&nbsp;&nbsp;&nbsp; 写这个指南的时候，计划是第五章写一个Fiber的应用例子，但是一时没有想到比较好的例子，模仿《Programming in Lua》中的多任务下载的例子也不合适，因为Ruby中的异步HttpClient跟lua还是很不一样的，体现不了Fiber的优点。因此，这第五节一直拖着没写。<br />
&nbsp;&nbsp;&nbsp; 恰巧最近在小组中做了一次Erlang的分享，有人问到Erlang调度器的实现问题，这块我没注意过，那时候就根据我对coroutine实现actor的想法做了下解释，后来思考了下那个解释是错误的，Erlang的调度器是抢占式的，而通过coroutine实现的actor调度却是非抢占的，两者还是截然不同的。我在《<a href="http://www.blogjava.net/killme2008/archive/2010/03/23/316273.html">Actor、Coroutine和Continuation的概念澄清</a>》中提到coroutine可以实现actor风格，actor跟coroutine并没有必然的联系，这篇文章的目的就在于证明这一点，使用Ruby Fiber实现一个简单的actor风格的库，整个代码不到100行。后面还会谈到这个实现的缺点，以及我对Erlang调度器实现的理解。<br />
<br />
&nbsp;&nbsp;&nbsp; 首先是monkey patch，给Thread和Fiber类加上两个方法，分别用于获取当前线程的调度器和Fiber对应的actor:<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Thread<br />
&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">得到当前线程的调度器</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">__scheduler__</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;@internal_scheduler</span><span style="color: #000000;">||=</span><span style="color: #000000;">FiberActor::Scheduler.new<br />
&nbsp;&nbsp;end<br />
end<br />
<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Fiber<br />
&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">得到当前Fiber的actor</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">__actor__</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;@internal_actor<br />
&nbsp;&nbsp;end<br />
end</span></div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 这里实现的actor仍然是Thread内的，一个Thread只跑一个调度器，每个actor关联一个Fiber。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 让我们来想想调度器该怎么实现,调度器顾名思义就是协调actor的运行，每次挑选适当的actor并执行，可以想象调度器内部应该维护一个等待调度的actor队列，Scheduler每次从队列里取出一个actor并执行，执行完之后取下一个actor执行，不断循环持续这个过程；在没有actor可以调度的时候，调度器应该让出执行权。因此调度器本身也是一个Fiber，它内部有个queue，用于维护等待调度的actor：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">module&nbsp;FiberActor<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Scheduler<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;initialize<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@queue</span><span style="color: #000000;">=</span><span style="color: #000000;">[]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@running</span><span style="color: #000000;">=</span><span style="color: #000000;">false<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;run<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;@running<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@running</span><span style="color: #000000;">=</span><span style="color: #000000;">true<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;true<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">取出队列中的actor并执行</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;actor</span><span style="color: #000000;">=</span><span style="color: #000000;">@queue.shift<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actor.fiber.resume<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rescue&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;ex<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">actor&nbsp;resume&nbsp;error,#{ex}</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">没有任务，让出执行权</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;reschedule<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;@running<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">已经启动，只是被挂起，那么再次执行</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@fiber.resume<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">将当前actor加入队列</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;Actor.current<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;running?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@running<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">(actor)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">将actor加入等待队列</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@queue&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;actor&nbsp;unless&nbsp;@queue.last&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;actor<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">启动调度器</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unless&nbsp;@running<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@queue&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;Actor.current<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@fiber</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;{&nbsp;run&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@fiber.resume<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;end<br />
end</span></div>
<br />
&nbsp;&nbsp;&nbsp; run方法是核心的调度方法，注释说明了主要的工作流程。因为调度器可能让出执行权，因此提供了reschedule方法重新resume启动调度器。&lt;&lt;方法用于将等待被调度的actor加入等待队列，如果调度器没有启动，那么就启动调度Fiber。<br />
<br />
&nbsp;&nbsp;&nbsp; 有了调度器，Actor的实现也很简单，Actor跟Fiber是一对一的关系，Actor内部维护一个mailbox，用来存储接收到的消息。最重要的是receive原语的实现，我们这里很简单，不搞模式匹配，只是接收消息。receive的工作流程大概是这样，判断mailbox中有没有消息，有消息的话，取出消息并调用block处理，没有消息的话就yield让出执行权。<br />
<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">module&nbsp;FiberActor&nbsp;&nbsp;<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Actor<br />
&nbsp;&nbsp;&nbsp;&nbsp;attr_accessor&nbsp;:fiber<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">定义类方法</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;self<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;scheduler<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.current.</span><span style="color: #800080;">__scheduler__</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;current<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Fiber.current.</span><span style="color: #800080;">__actor__</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">启动一个actor</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;spawn(</span><span style="color: #000000;">*</span><span style="color: #000000;">args,</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">block)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fiber</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;block.call(args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actor</span><span style="color: #000000;">=</span><span style="color: #000000;">new(fiber)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fiber.instance_variable_set&nbsp;:@internal_actor,actor<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scheduler&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;actor<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;actor<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;receive(</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">block)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current.receive(</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">block)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;initialize(fiber)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mailbox</span><span style="color: #000000;">=</span><span style="color: #000000;">[]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@fiber</span><span style="color: #000000;">=</span><span style="color: #000000;">fiber<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">给actor发送消息</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;(msg)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mailbox&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;msg<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">加入调度队列</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Actor.scheduler&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;self<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;receive(</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">block)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">没有消息的时候，让出执行权</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;@mailbox.empty?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;msg</span><span style="color: #000000;">=</span><span style="color: #000000;">@mailbox.shift<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;block.call(msg)<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;alive?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@fiber.alive?<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;end<br />
<br />
end</span></div>
<br />
&nbsp;&nbsp;&nbsp; Actor.spawn用于启动一个actor，内部其实是创建了一个fiber并包装成actor给用户，每个actor一被创建就加入调度器的等待队列。&lt;&lt;方法用于向actor传递消息，传递消息后，该actor也将加入等待队列，等待被调度。<br />
<br />
&nbsp;&nbsp;&nbsp; 我们的简化版actor库已经写完了，可以尝试写几个例子，最简单的hello world:<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">include&nbsp;FiberActor<br />
<br />
Actor.spawn&nbsp;{&nbsp;puts&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">hello&nbsp;world!</span><span style="color: #800000;">"</span><span style="color: #000000;">}<br />
</span></div>
&nbsp;&nbsp;&nbsp;&nbsp; 输出：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">hello&nbsp;world!</span></div>
<br />
&nbsp;&nbsp;&nbsp; 没有问题，那么试试传递消息：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">actor</span><span style="color: #000000;">=</span><span style="color: #000000;">Actor.spawn{<br />
&nbsp;&nbsp;&nbsp;Actor.receive{&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">msg</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;&nbsp;puts&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">receive&nbsp;#{msg}</span><span style="color: #800000;">"</span><span style="color: #000000;">}<br />
}<br />
actor&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;:test_message<br />
</span></div>
&nbsp;&nbsp;&nbsp; 输出：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">receive&nbsp;test_message</span></div>
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 也成了，那么试试两个actor互相传递消息，乒乓一下下：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">pong</span><span style="color: #000000;">=</span><span style="color: #000000;">Actor.spawn&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Actor.receive&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">ping</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">收到ping，返回pong</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ping&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;:pong<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
ping</span><span style="color: #000000;">=</span><span style="color: #000000;">Actor.spawn&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">ping一下，将ping作为消息传递</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pong&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;Actor.current<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Actor.receive&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">msg</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">接收到pong</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">ping&nbsp;#{msg}</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
</span><span style="color: #008000;">#</span><span style="color: #008000;">resume调度器</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">Actor.scheduler.reschedule<br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 输出：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">ping&nbsp;pong</span></div>
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; 都没有问题，这个超级简单actor基本完成了。可以看到，利用coroutine来实现actor是完全可行的，事实上我这里描述的实现基本上是<a href="http://revactor.org/">revactor</a>这个库的实现原理。<a href="http://revactor.org/">revactor</a>是一个ruby的actor库，它的实现就是基于Fiber，并且支持消息的模式匹配和thread之间的actor调度，有兴趣地可以去玩下。更进一步，其实采用轻量级协程来模拟actor风格早就不是新鲜主意，比如在<a href="http://www.ecug.org/lecturer/">cn-erlounge的第四次会议上</a>就有两个topic是关于这个，一个是51.com利用基于ucontext的实现的类erlang进程模型，一个是许世伟的CERL。可以想见，他们的基本原理跟本文所描述不会有太大差别，那么面对的问题也是一样。<br />
<br />
&nbsp; &nbsp;&nbsp; 采用coroutine实现actor的主要缺点如下：<br />
1、因为是非抢占式，这就要求actor不能有阻塞操作，任何阻塞操作都需要异步化。IO可以使用异步IO，没有os原生支持的就需要利用线程池，基本上是一个重复造轮子的过程。<br />
2、异常的隔离，某个actor的异常不能影响到调度器的运转，简单的try...catch是不够的。<br />
3、多核的利用，调度器只能跑在一个线程上，无法充分利用多核优势。<br />
4、效率因素，在actor数量剧增的情况下，简单的FIFO的调度策略效率是个瓶颈，尽管coroutine的切换已经非常高效。<br />
<br />
&nbsp;&nbsp;&nbsp; 当然，上面提到的这些问题并非无法解决，例如可以使用多线程多个调度器，类似erlang smp那样来解决单个调度器的问题。但是如调度效率这样的问题是很难解决的。相反，erlang的actor实现就不是通过coroutine，而是自己实现一套类似os的调度程序。<br />
&nbsp;&nbsp;&nbsp; 首先明确一点，Erlang的process的调度是抢占式的，而非couroutine的协作式的。其次，Erlang早期版本是只有一个调度器，运行在一个线程上，随着erts的发展，现在erlang的调度器已经支持smp，每个cpu关联一个调度器，并且可以明确指定哪个调度器绑定到哪个cpu上。第三，Erlang的调度也是采用优先队列+时间片轮询的方式，每个调度器关联一个<span id=":2v1">ErtsRunQueue<wbr>，</span><span id=":2v1">ErtsRunQueue<wbr>内部又分为三个</span><span id=":2n7">ErtsRunPrioQu<wbr>eue队列，分别对应high,max和normal,low的优先级，其中normal和low共用一个队列；在Erlang中时间片是以reduction为单位，你可以将reduction理解成一次函数调用，每个被调度的process能执行的reduction次数是有限的。调度器每次都是从max</span>队列开始寻找等待调度的process并执行，当前调度的队列如果为空或者执行的reductions超过限制，那么就降低优先级，调度下一个队列。<br />
<br />
&nbsp;&nbsp; 从上面的描述可以看出，Erlang优秀的地方不仅在于actor风格的轻量级process，另一个强悍的地方就是它的类os的调度器，再加上OTP库的完美支持，这不是一般方案能山寨的。<br />
&nbsp;&nbsp; &nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; <br /><img src ="http://www.blogjava.net/killme2008/aggbug/318182.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2010-04-13 18:31 <a href="http://www.blogjava.net/killme2008/archive/2010/04/13/318182.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang简介的PPT（达人勿入）</title><link>http://www.blogjava.net/killme2008/archive/2010/04/12/318031.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 12 Apr 2010 02:45:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/04/12/318031.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/318031.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/04/12/318031.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/318031.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/318031.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 在小组内做的一次分享，基本上是在锋爷的一个PPT的基础上做了一些扩充，对Erlang没有了解过的朋友可以看看。<br />
<br />
<div style="width: 550px;" id="__ss_3694293"><strong style="margin: 12px 0pt 4px; display: block;"><a href="http://www.slideshare.net/killme2008/erlang-3694293" title="Erlang简介">Erlang简介</a></strong><object width="550" height="400">
<param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=erlang-100411213639-phpapp02&stripped_title=erlang-3694293" />
<param name="allowFullScreen" value="true"/>
<param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=erlang-100411213639-phpapp02&stripped_title=erlang-3694293" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="550" height="400"></embed></object>
<div style="padding: 5px 0pt 12px;">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/killme2008">dennis zhuang</a>.</div>
</div><img src ="http://www.blogjava.net/killme2008/aggbug/318031.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2010-04-12 10:45 <a href="http://www.blogjava.net/killme2008/archive/2010/04/12/318031.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Rabbitmq的网络层浅析</title><link>http://www.blogjava.net/killme2008/archive/2009/11/29/304079.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 29 Nov 2009 04:00:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2009/11/29/304079.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/304079.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2009/11/29/304079.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/304079.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/304079.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 最近在锋爷的建议下开始读rabbitmq的源码，锋爷说这个项目已经很成熟，并且代码也很有借鉴和学习的意义，在自己写erlang代码之前看看别人是怎么写的，可以少走弯路，避免养成一些不好的习惯，学习一些最佳实践。读了一个星期，这个项目果然非常棒，代码也写的非常清晰易懂，一些细节的处理上非常巧妙，比如我这里想分享的网络层一节。<br />
&nbsp;&nbsp;&nbsp; Rabbitmq是一个MQ系统，也就是消息中间件，它实现了AMQP 0.8规范，简单来说就是一个TCP的广播服务器。AMQP协议，你可以类比JMS，不过JMS仅仅是java领域内的API规范，而AMQP比JMS更进一步，它有自己的wire-level protocol，有一套可编程的协议，中立于语言。简单介绍了Rabbitmq之后，进入正题。<br />
&nbsp;&nbsp;&nbsp; Rabbitmq充分利用了Erlang的分布式、高可靠性、并发等特性，首先看它的一个结构图：<br />
<div id="yv_." style="text-align: left;"><img style="width: 648px; height: 486px;" src="http://docs.google.com/File?id=ddxkntwd_135zpwntjg2_b" alt="" /><br />
<br />
这张图展现了Rabbitmq的主要组件和组件之间的关系，具体到监控树的结构，我画了一张图：<br />
<br />
<div id="kahs" style="text-align: left;"><img style="width: 645px; height: 470px;" src="http://docs.google.com/File?id=ddxkntwd_131d9bnbtcm_b" alt="" /><br />
<br />
<br />
</div>
<br />
</div>
<br />
<br />
&nbsp;&nbsp;&nbsp; <strong>顶层是rabbit_sup
supervisor，它至少有两个子进程，一个是rabbit_tcp_client_sup，用来监控每个connection的处理进程
rabbit_reader的supervisor;rabbit_tcp_listener_sup是监控tcp_listener和
tcp_acceptor_sup的supervisor，tcp_listener里启动tcp服务器，监听端口，并且通过tcp_acceptor_sup启动N个tcp_accetpor，tcp_acceptor发起accept请求，等待客户端连接;tcp_acceptor_sup负责监控这些acceptor。这张图已经能给你一个大体的印象。</strong><br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 讲完大概，进入细节，说说几个我觉的值的注意的地方：<br />
1、<strong>tcp_accepto.erl,r对于accept采用的是异步方式</strong>，利用<strong>prim_inet:async_accept/2</strong>方
法，此模块没有被文档化，是otp库内部使用,通常来说没必要使用这一模块，gen_tcp:accept/1已经足够，不过rabbitmq是广播程
序，因此采用了异步方式。使用async_accept，需要打patch，以使得socket好像我们从gen_tcp:accept/1得到的一样：<br />
<br />
handle_info({inet_async, LSock, Ref, {ok, Sock}},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; State = #state{callback={M,F,A}, sock=LSock, ref=Ref}) -&gt;<br />
&nbsp;&nbsp;&nbsp; %%这里做了patch<br />
&nbsp;&nbsp;&nbsp; %% patch up the socket so it looks like one we got from<br />
&nbsp;&nbsp;&nbsp; %% gen_tcp:accept/1 <br />
&nbsp;&nbsp;&nbsp; <strong>{ok, Mod} = inet_db:lookup_socket(LSock),<br />
&nbsp;&nbsp;&nbsp; inet_db:register_socket(Sock, Mod),<br />
</strong><br />
&nbsp;&nbsp;&nbsp; try<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %% report<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {Address, Port}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = inet_op(fun () -&gt; inet:sockname(LSock) end),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {PeerAddress, PeerPort} = inet_op(fun () -&gt; inet:peername(Sock) end),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; error_logger:info_msg("accepted TCP connection on ~s:~p from ~s:~p~n",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [inet_parse:ntoa(Address), Port,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inet_parse:ntoa(PeerAddress), PeerPort]),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %% 调用回调模块，将Sock作为附加参数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; apply(M, F, A ++ [Sock])<br />
&nbsp;&nbsp;&nbsp; catch {inet_error, Reason} -&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gen_tcp:close(Sock),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; error_logger:error_msg("unable to accept TCP connection: ~p~n",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Reason])<br />
&nbsp;&nbsp;&nbsp; end,<br />
<br />
&nbsp;&nbsp;&nbsp; %% 继续发起异步调用<br />
&nbsp;&nbsp;&nbsp; case prim_inet:async_accept(LSock, -1) of<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, NRef} -&gt; {noreply, State#state{ref=NRef}};<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Error -&gt; {stop, {cannot_accept, Error}, none}<br />
&nbsp;&nbsp;&nbsp; end;<br />
%%处理错误情况<br />
handle_info({inet_async, LSock, Ref, {error, closed}},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; State=#state{sock=LSock, ref=Ref}) -&gt;<br />
&nbsp;&nbsp;&nbsp; %% It would be wrong to attempt to restart the acceptor when we<br />
&nbsp;&nbsp;&nbsp; %% know this will fail.<br />
&nbsp;&nbsp;&nbsp; {stop, normal, State};<br />
<br />
2、<strong>rabbitmq内部是使用了多个并发acceptor</strong>，这在高并发下、大量连接情况下有效率优势，<strong>类似java现在的nio框架采用多个reactor类似</strong>，查看tcp_listener.erl:<br />
<br />
init({IPAddress, Port, SocketOpts,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ConcurrentAcceptorCount, AcceptorSup,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {M,F,A} = OnStartup, OnShutdown, Label}) -&gt;<br />
&nbsp;&nbsp;&nbsp; process_flag(trap_exit, true),<br />
&nbsp;&nbsp;&nbsp; case gen_tcp:listen(Port, SocketOpts ++ [{ip, IPAddress},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {active, false}]) of<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, LSock} -&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %%创建ConcurrentAcceptorCount个并发acceptor<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong> lists:foreach(fun (_) -&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, _APid} = supervisor:start_child(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AcceptorSup, [LSock])<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lists:duplicate(ConcurrentAcceptorCount, dummy)),</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, {LIPAddress, LPort}} = inet:sockname(LSock),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; error_logger:info_msg("started ~s on ~s:~p~n",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Label, inet_parse:ntoa(LIPAddress), LPort]),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %%调用初始化回调函数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; apply(M, F, A ++ [IPAddress, Port]),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, #state{sock = LSock,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; on_startup = OnStartup, on_shutdown = OnShutdown, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label = Label}};<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {error, Reason} -&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; error_logger:error_msg(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "failed to start ~s on ~s:~p - ~p~n",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Label, inet_parse:ntoa(IPAddress), Port, Reason]),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {stop, {cannot_listen, IPAddress, Port, Reason}}<br />
&nbsp;&nbsp;&nbsp; end.<br />
<br />
这里有一个技巧，如果要循环N次执行某个函数F，可以通过lists:foreach结合lists:duplicate(N,dummy)来处理。<br />
<br />
<strong>lists:foreach(fun(_)-&gt; F() end,lists:duplicate(N,dummy)).</strong><br />
<br />
3、<strong>simple_one_for_one策略的使用</strong>，可以看到对于tcp_client_sup和tcp_acceptor_sup都采用了simple_one_for_one策略，而非普通的one_fo_one，这是为什么呢？<br />
这牵扯到simple_one_for_one的几个特点：<br />
<strong>1)simple_one_for_one内部保存child是使用dict，而其他策略是使用list</strong>，因此simple_one_for_one更适合child频繁创建销毁、需要大量child进程的情况，具体来说例如网络连接的频繁接入断开。<br />
<strong>2)使用了simple_one_for_one后，无法调用terminate_child/2 delete_child/2 restart_child/2 <br />
<br />
</strong>3)start_child/2
对于simple_one_for_one来说，不必传入完整的child
spect，传入参数list，会自动进行<strong>参数合并</strong>。<strong>在一个地方定义好child
spec之后，其他地方只要start_child传入参数即可启动child进程，简化child都是同一类型进程情况下的编程</strong>。<br />
<br />
在
rabbitmq中，tcp_acceptor_sup的子进程都是tcp_acceptor进程，在tcp_listener中是启动了
ConcurrentAcceptorCount个tcp_acceptor子进程，通过supervisor:start_child/2方法：<br />
<br />
%%创建ConcurrentAcceptorCount个并发acceptor<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lists:foreach(fun (_) -&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, _APid} = <strong>supervisor:start_child(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AcceptorSup, [</strong><strong>LSock])</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lists:duplicate(ConcurrentAcceptorCount, dummy)),<br />
<br />
注意到，这里调用的start_child只传入了<strong>LSock</strong>一个参数，另一个参数CallBack是在定义child spec的时候传入的，参见tcp_acceptor_sup.erl:<br />
init(Callback) -&gt;<br />
&nbsp;&nbsp;&nbsp; {ok, {{simple_one_for_one, 10, 10},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{tcp_acceptor, {tcp_acceptor, start_link, [<strong>Callback</strong>]},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transient, brutal_kill, worker, [tcp_acceptor]}]}}.<br />
<br />
Erlang内部自动为simple_one_for_one做了<strong>参数合并</strong>，最后调用的是tcp_acceptor的init/2:<br />
<br />
init({<strong>Callback</strong>, <strong>LSock</strong>}) -&gt;<br />
&nbsp;&nbsp;&nbsp; case prim_inet:async_accept(LSock, -1) of<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, Ref} -&gt; {ok, #state{callback=Callback, sock=LSock, ref=Ref}};<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Error -&gt; {stop, {cannot_accept, Error}}<br />
&nbsp;&nbsp;&nbsp; end.<br />
<br />
对于tcp_client_sup的情况类似，tcp_client_sup监控的子进程都是rabbit_reader类型，在
rabbit_networking.erl中启动tcp_listenner传入的处理connect事件的回调方法是是
rabbit_networking:start_client/1:<br />
<br />
start_tcp_listener(Host, Port) -&gt;<br />
&nbsp;&nbsp;&nbsp; start_listener(Host, Port, "TCP Listener",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %回调的MFA<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<strong>?MODULE, start_client, []</strong>}).<br />
<br />
start_client(Sock) -&gt;<br />
&nbsp;&nbsp;&nbsp; {ok, Child} = supervisor:start_child(rabbit_tcp_client_sup, []),<br />
&nbsp;&nbsp;&nbsp; ok = rabbit_net:controlling_process(Sock, Child),<br />
&nbsp;&nbsp;&nbsp; Child ! {go, Sock},<br />
&nbsp;&nbsp;&nbsp; Child.<br />
<br />
start_client调用了supervisor:start_child/2来动态启动rabbit_reader进程。<br />
<br />
4、<strong>协议的解析，消息的读取</strong>这部分也非常巧妙，这一部分主要在rabbit_reader.erl中，对于协议的解析没有采用gen_fsm，而是实现了一个巧妙的状态机机制,核心代码在mainloop/4中：<br />
%启动一个连接<br />
start_connection(Parent, Deb, ClientSock) -&gt;<br />
&nbsp;&nbsp;&nbsp; process_flag(trap_exit, true),<br />
&nbsp;&nbsp;&nbsp; {PeerAddressS, PeerPort} = peername(ClientSock),<br />
&nbsp;&nbsp;&nbsp; ProfilingValue = setup_profiling(),<br />
&nbsp;&nbsp;&nbsp; try <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rabbit_log:info("starting TCP connection ~p from ~s:~p~n",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [self(), PeerAddressS, PeerPort]),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %延时发送握手协议<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a title="" href="http://www.erlang.org">Erlang</a>:send_after(?HANDSHAKE_TIMEOUT * 1000, self(),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; handshake_timeout),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %进入主循环，更换callback模块，魔法就在这个switch_callback<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mainloop(Parent, Deb, switch_callback(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #v1{sock = ClientSock,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connection = #connection{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user = none,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeout_sec = ?HANDSHAKE_TIMEOUT,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; frame_max = ?FRAME_MIN_SIZE,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; vhost = none},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; callback = uninitialized_callback,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recv_ref = none,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connection_state = pre_init},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>%%注意到这里，handshake就是我们的回调模块，8就是希望接收的数据长度，AMQP协议头的八个字节。</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; handshake, 8))<br />
<br />
魔法就在switch_callback这个方法上：<br />
<strong>switch_callback(OldState, NewCallback, Length) -&gt;<br />
&nbsp;&nbsp;&nbsp; %发起一个异步recv请求，请求Length字节的数据<br />
&nbsp;&nbsp;&nbsp; Ref = inet_op(fun () -&gt; rabbit_net:async_recv(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OldState#v1.sock, Length, infinity) end),<br />
&nbsp;&nbsp;&nbsp; %更新状态，替换ref和处理模块<br />
&nbsp;&nbsp;&nbsp; OldState#v1{callback = NewCallback,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recv_ref = Ref}.</strong><br />
<br />
异步接收Length个数据，如果有，erlang会通知你处理。处理模块是什么概念呢？其实就是一个状态的概念，表示当前协议解析进行到哪一步，起一个label的作用，看看mainloop/4中的应用：<br />
<br />
mainloop(Parent, Deb, State = #v1{sock= Sock, recv_ref = Ref}) -&gt;<br />
&nbsp;&nbsp;&nbsp; %%?LOGDEBUG("Reader mainloop: ~p bytes available, need ~p~n", [HaveBytes, WaitUntilNBytes]),<br />
&nbsp;&nbsp;&nbsp; receive<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %%接收到数据，交给handle_input处理,注意handle_input的第一个参数就是callback<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {inet_async, Sock, Ref, {ok, Data}} -&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %handle_input处理<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {State1, Callback1, Length1} =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>handle_input(State#v1.callback, Data,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; State#v1{recv_ref = none}),</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %更新回调模块，再次发起异步请求，并进入主循环<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mainloop(Parent, Deb,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch_callback(State1, Callback1, Length1));<br />
<br />
<br />
handle_input有多个分支，每个分支都对应一个处理模块，例如我们刚才提到的握手协议：<br />
<br />
%handshake模块，注意到第一个参数，第二个参数就是我们得到的数据<br />
handle_input(<strong>handshake</strong>, &lt;&lt;"AMQP",1,1,ProtocolMajor,ProtocolMinor&gt;&gt;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; State = #v1{sock = Sock, connection = Connection}) -&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; %检测协议是否兼容<br />
&nbsp;&nbsp;&nbsp; case check_version({ProtocolMajor, ProtocolMinor},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {?PROTOCOL_VERSION_MAJOR, ?PROTOCOL_VERSION_MINOR}) of<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true -&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, Product} = application:get_key(id),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, Version} = application:get_key(vsn),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %兼容的话，进入connections start，协商参数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ok = send_on_channel0(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sock,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #'connection.start'{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; version_major = ?PROTOCOL_VERSION_MAJOR,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; version_minor = ?PROTOCOL_VERSION_MINOR,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; server_properties =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{list_to_binary(K), longstr, list_to_binary(V)} ||<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {K, V} &lt;-<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{"product",&nbsp;&nbsp;&nbsp;&nbsp; Product},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {"version",&nbsp;&nbsp;&nbsp;&nbsp; Version},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {"platform",&nbsp;&nbsp;&nbsp; "<a title="" href="http://www.erlang.org">Erlang</a>/OTP"},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {"copyright",&nbsp;&nbsp; ?COPYRIGHT_MESSAGE},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {"information", ?INFORMATION_MESSAGE}]],<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mechanisms = &lt;&lt;"PLAIN AMQPLAIN"&gt;&gt;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; locales = &lt;&lt;"en_US"&gt;&gt; }),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {State#v1{connection = Connection#connection{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeout_sec = ?NORMAL_TIMEOUT},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connection_state = starting},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; frame_header, 7};<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %否则，断开连接，返回可以接受的协议<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false -&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw({bad_version, ProtocolMajor, ProtocolMinor})<br />
&nbsp;&nbsp;&nbsp; end;<br />
<br />
&nbsp;&nbsp;&nbsp; 其他协议的处理也是类似，通过动态替换callback的方式来模拟状态机做协议的解析和数据的接收，真的很巧妙！让我们体会到Erlang的魅力，FP的魅力。<br />
<br />
<strong>5、序列图：</strong><br />
1）tcp server的启动过程：<br />
<div id="kauz" style="text-align: left;"><img style="width: 648px; height: 491.195px;" src="http://docs.google.com/File?id=ddxkntwd_134f36cc8hm_b" alt="" /></div>
<br />
2）一个client连接上来的处理过程：<br />
<div id="d.1n" style="text-align: left;"><img style="width: 648px; height: 750.115px;" src="http://docs.google.com/File?id=ddxkntwd_133gn88c5cs_b" alt="" /></div>
<br />
<br />
&nbsp;&nbsp;&nbsp;
小结：从上面的分析可以看出,rabbitmq的网络层是非常健壮和高效的，通过层层监控，对每个可能出现的风险点都做了考虑，并且利用了prim_net模块做异步IO处理。分层也是很清晰，将业务处理模块隔离到client_sup监控下的子进程，将网络处理细节和业务逻辑分离。在协议的解析和业务处理上虽然没有采用gen_fsm，但是也实现了一套类似的状态机机制，通过动态替换Callback来模拟状态的变迁，非常巧妙。如果你要实现一个tcp server，强烈推荐从rabbitmq中扣出这个网络层，你只需要实现自己的业务处理模块即可拥有一个高效、健壮、分层清晰的TCP服务器。<br /><img src ="http://www.blogjava.net/killme2008/aggbug/304079.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2009-11-29 12:00 <a href="http://www.blogjava.net/killme2008/archive/2009/11/29/304079.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang Web Shell(update)</title><link>http://www.blogjava.net/killme2008/archive/2009/11/19/302967.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 19 Nov 2009 11:22:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2009/11/19/302967.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/302967.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2009/11/19/302967.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/302967.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/302967.html</trackback:ping><description><![CDATA[update：修复了在linux firefox上不兼容的BUG。<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; 下午搞了个<a href="http://code.google.com/p/erlwsh/">Erlang web shell</a>，可以在web页面上像eshell那样进行交互式的Erlang编程，方便学习和测试。这样一来，一个<a href="http://code.google.com/p/erlwsh/">erlwsh</a>就可以服务多个client，只要你有网络和浏览器，随时随地可以敲上几行erlang看看结果。代码很简单，就不多说了，有兴趣的看看，通过<a href="http://code.google.com/p/mochiweb/">mochiweb</a>的http chunk编码，client通过Ajax Post方式提交。眼见为实，看看运行截图：<br />
<br />
<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/killme2008/erlwsh.png" width="459" height="803" /><br />
<br />
<br />
&nbsp;&nbsp;&nbsp; 工程在google code上： <a title="http://code.google.com/p/erlwsh/" href="http://code.google.com/p/erlwsh/">http://code.google.com/p/erlwsh/</a><br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 安装很简单，首先确保你已经安装了<a href="www.erlang.org">Erlang</a>，接下来：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">svn&nbsp;checkout&nbsp;http:</span><span style="color: #008000;">//</span><span style="color: #008000;">erlwsh.googlecode.com/svn/trunk/&nbsp;erlwsh-read-only</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">cd&nbsp;erlwsh</span><span style="color: #000000;">-</span><span style="color: #000000;">read</span><span style="color: #000000;">-</span><span style="color: #000000;">only<br />
</span><span style="color: #000000;">scripts</span><span style="color: #000000;">/</span><span style="color: #000000;">install_mochiweb.sh</span><br />
<span style="color: #000000;">make<br />
</span><span style="color: #000000;">.</span><span style="color: #000000;">/</span><span style="color: #000000;">start.sh</span></div>
<tt id="checkoutcmd"><br />
&nbsp;&nbsp;&nbsp; 因为需要使用mochiweb，所以提供了下载并自动安装的脚本，这是litaocheng的大作。启动后访问 http://localhost:8000/shell 即可，have fun.<br />
<br />
</tt><br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/302967.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2009-11-19 19:22 <a href="http://www.blogjava.net/killme2008/archive/2009/11/19/302967.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ets和dets的效率建议</title><link>http://www.blogjava.net/killme2008/archive/2007/09/27/148764.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 27 Sep 2007 08:33:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/09/27/148764.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/148764.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/09/27/148764.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/148764.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/148764.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; ets表的底层是由哈希表实现的,不过ordered_set例外,它是由平衡二叉树实现的。 所以不管是插入还是查找,set的效率要比ordered_set高.采用set还是ordered_set取决于你的需求，当你需要一个有序的集合时，显然应当采用ordered_set模式。<br />
<br />
duplicate_bag要比bag的效率要高, 因为bag要和原来的记录比较是否有相同的记录已经插入. 如果数据量很大,相同的记录越多,bag的效率就越差. <br />
<br />
一张ets表是由创建它的进程所拥有, 当此进程调用ets:delete或者进程终止的时候, ets表就会被删除. <br />
<br />
一般情况下, 插入一个元组到一张ets表中, 所有代表这个元组的结构都会被从process的堆栈中,复制到ets表中; 当查找一条记录时, 结果tuple从ets表中复制到进程的堆栈中。 <br />
<br />
但是large binaries却不是这样! 它们被存入自已所拥有的off-heap
area中。这个区域可以被多个process,ets表,和binaries所共享。它由引用计数的垃圾回收策略管理,
这个策略会跟踪到底有多少个process/ets表/binaries引用了这个large binaries. 如果引用数为0的话, 此大型二进制数据就会被垃圾回收掉. <br />
<br />
看起来很复杂, 实际结论就是: 两进程间发送包含大型binary数据的消息其实费用很低, 往ets表插入binary类型元组也很划算。我们应该尽可能采用binaries来实现字符串或无类型的大数据块.<img src ="http://www.blogjava.net/killme2008/aggbug/148764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-09-27 16:33 <a href="http://www.blogjava.net/killme2008/archive/2007/09/27/148764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang之IO编程</title><link>http://www.blogjava.net/killme2008/archive/2007/09/27/148747.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 27 Sep 2007 08:03:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/09/27/148747.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/148747.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/09/27/148747.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/148747.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/148747.html</trackback:ping><description><![CDATA[Erlang用于操纵文件I/O的模块有：<br />
file模块：打开、读、写、关闭文件已经操作目录的方法基本都在这里<br />
<br />
filename模块：提供平台独立方式用于操纵文件名<br />
<br />
filelib模块：file模块的扩展，提供了更多的实用工具，在file模块基础上构建<br />
<br />
io模块：一系列用于操作打开的文件的方法，解析格式、格式化输出等等。<br />
<br />
1.打开文件：<br />
{ok,F}=file:open("data1.dat",read). %读模式打开<br />
{ok,F}=file:open("data1.dat",write). %写模式<br />
{ok,F}=file:open("data1.dat",[read,write]). %读、写、二进制模式<br />
<br />
支持的所有模式参见文档。<br />
<br />
2.读取：<br />
(1)如果以一个Erlang term的方式读取，采用:<br />
io:read(F,'').<br />
其中第二个参数是提示符，用于在标准输入时作为提示。<br />
这个方法有一个变形read/3<br />
<a name="read/3"><strong><code>read(IoDevice, Prompt, StartLine)</code></strong></a><br />
第三个参数用于指定开始行数。<br />
<br />
(2)如果是按字节读取，文件必须按raw模式打开采用：<br />
{ok, Data}=file:read(F,100).<br />
<br />
(3)按行读取：<br />
io:get_line(F, '').<br />
<br />
(4)读取整个文件的内容：<br />
{ok,Binary}=file:read_file("data1.dat").<br />
注意返回的是一个binary类型<br />
<br />
(5)随机读取：<br />
{ok,Binary}=file:pread(F, 22, 46).<br />
<br />
其中第二个参数是开始位置，第三个参数是读取的长度，返回的也是binary类型。<br />
<br />
3.写入文件：<br />
(1)采用io:format/3方法：<br />
{ok, S} = file:open("test2.dat", write).<br />
io:format(S, "~s~n", ["Hello readers"]).<br />
io:format(S, "~w~n", [123]).<br />
<br />
其中的~开头的字符是一个个格式化命令，比如常见的：<br />
~c&nbsp;&nbsp; anscii码<br />
~f&nbsp;&nbsp; 浮点数<br />
~s&nbsp;&nbsp; 字符串<br />
~w&nbsp;&nbsp; <a title="" href="http://www.erlang.org" >Erlang</a> term<br />
~p&nbsp;&nbsp; 与~w类似，不过当多行时将自动换行<br />
~n&nbsp;&nbsp; 显然，换行符<br />
<br />
（2）写入整个文件：<br />
file:write_file(File, IO)<br />
<br />
其中IO可以为list、integer或者binary类型<br />
<br />
（3）随机写入：<br />
file:pwrite(F, 10, &lt;&lt;"new"&gt;&gt;)<br />
<br />
4.关闭文件:<br />
file:close(F).<br />
<br />
5.目录操作：<br />
都是linux命令风格的操作，<br />
cd("/home/dennis/").&nbsp; %进入目录<br />
file:list_dir(".").&nbsp;&nbsp; %列出当前目录文件<br />
file:make_dir("test").&nbsp; %创建test目录<br />
file:del_dir("test").&nbsp;&nbsp; %删除test目录<br />
<br />
6.获取文件信息，比如文件大小，最后修改时间等等。调用file:read_file_info/1方法，该方法返回一个file_info记录类型，里面拥有文件的具体信息，比如type、size等。<br />
{ok, Facts} =file:read_file_info(File).<br />
io:format("~s~n",{Facts#file_info.type, Facts#file_info.size}).<br />
<br />
7.复制和删除文件：<br />
file:copy(Source, Destination).<br />
file:delete(File).<br />
<br />
&nbsp;&nbsp;&nbsp; 这个笔记仅仅记录了一些常用到的方法，一些高级的工具方法并没有涉及，具体参考Erlang的文档。<br />
<br />
<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/148747.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-09-27 16:03 <a href="http://www.blogjava.net/killme2008/archive/2007/09/27/148747.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简单的web server性能测试</title><link>http://www.blogjava.net/killme2008/archive/2007/08/29/141036.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 29 Aug 2007 10:10:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/08/29/141036.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/141036.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/08/29/141036.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/141036.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/141036.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 简单的web server性能测试，一般多线程方式与采用jdk5线程池的比较。&nbsp;&nbsp;<a href='http://www.blogjava.net/killme2008/archive/2007/08/29/141036.html'>阅读全文</a><img src ="http://www.blogjava.net/killme2008/aggbug/141036.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-08-29 18:10 <a href="http://www.blogjava.net/killme2008/archive/2007/08/29/141036.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang ring benchmark</title><link>http://www.blogjava.net/killme2008/archive/2007/08/04/134417.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 04 Aug 2007 09:46:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/08/04/134417.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/134417.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/08/04/134417.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/134417.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/134417.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 这是Programming Erlang第8章节的一个练习，创建N个process，连接成一个圈，然后在这个圈子里发送消息M次，看看时间是多少，然后用另一门语言写同样的程序，看看时间是多少。我自己写的版本在处理3000个进程，1000次消息循环（也就是300万次消息传递）时花了5秒多，后来去google别人写的版本，竟然让我找到一个98年做的benchmark：Erlang vs. java，也是同样的的问题。测试的结果是Erlang性能远远大于java，这也是显然的结果，Erlang的process是轻量级、无共享的，而java的线程是os级别的，两者创建的cost不可同日而语。详细的比较请看<a href="http://www.sics.se/%7Ejoe/ericsson/du98024.html">这里</a><br>&nbsp;&nbsp;&nbsp; 不过我分析了这个测试里的Erlang代码，存在问题，并没有完成所有的循环，进程就结束了，这对比较结果有较大的影响。原始代码如下：<br><br>
<pre>-module(zog).<br><br>%% This is a test program that first creates N processes (that are<br>%% "connected" in a ring) and then sends M messages in that ring.<br>%%<br>%% - September 1998<br>%% - roland<br><br><br>-export([start/0, start/1, start/2]).<br><br>-export([run/2, process/1]).			% Local exports - ouch<br><br>start() -&gt; start(16000).<br><br>start(N) -&gt; start(N, 1000000).<br><br>start(N, M) -&gt; spawn(?MODULE, run, [N, M]).<br><br><br>run(N, M) when N &lt; 1 -&gt;<br>    io:format("Must be at least 1 process~n", []),<br>    0.0;<br>run(N, M) -&gt;<br>    statistics(wall_clock),<br><br>    Pid = setup(N-1, self()),<br><br>    {_,T1} = statistics(wall_clock),<br>    io:format("Setup : ~w s", [T1/1000]),<br>    case N of<br>	1 -&gt; io:format(" (0 spawns)~n", []);<br>	_ -&gt; io:format(" (~w us per spawn) (~w spawns)~n",<br>		       [1000*T1/(N-1), N-1])<br>    end,<br>    statistics(wall_clock),<br><br>    Pid ! M,<br>    K = process(Pid),<br><br>    {_,T2} = statistics(wall_clock),<br>    Time = 1000*T2/(M+K),<br>    io:format("Run   : ~w s (~w us per msg) (~w msgs)~n",<br>	      [T2/1000, Time, (M+K)]),<br><br>    Time.<br><br>setup(0, OldPid) -&gt;<br>    OldPid;<br>setup(N, OldPid) -&gt;<br>    NewPid = spawn(?MODULE, process, [OldPid]),<br>    setup(N-1, NewPid).<br><br><br>process(Pid) -&gt;<br>    receive<br>	M -&gt;<br>	    Pid ! M-1,<br>	    if<br>		M &lt; 0  -&gt; -M;<br>		true   -&gt; process(Pid)<br>	    end<br>    end.</pre>
&nbsp;
<span style="font-weight: bold;">我将process修改一下</span>：<br>
<pre>process(Pid) -&gt;<br>    receive<br>	M -&gt;<br>	    Pid ! M-1,<br>            io:format("form ~w to ~w~n",[self(),Pid]),<br>	    if<br>		M &lt; 0  -&gt; -M;<br>		true   -&gt; process(Pid)<br>	    end<br>    end.</pre>
然后执行下zog:run(3,3)，<span style="font-weight: bold;">你将发现消息绕了两圈就结束了，第三圈根本没有进行</span>，不知道测试者是什么用意。<span style="font-weight: bold;">依照现在的执行300万次消息传送竟然只需要3毫秒</span>！我修改了下了下代码如下：<br>-module(zog).<br><br>%% This is a test program that first creates N processes (that are<br>%% "connected" in a ring) and then sends M messages in that ring.<br>%%<br>%% - September 1998<br>%% - roland<br>-export([start/0, start/1, start/2]).<br><br>-export([run/2, process/2]).&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; % Local exports - ouch<br><br>start() -&gt; start(16000).<br><br>start(N) -&gt; start(N, 1000000).<br><br>start(N, M) -&gt; spawn(?MODULE, run, [N, M]).<br><br><br>run(N, M) when N &lt; 1 -&gt;<br>&nbsp;&nbsp;&nbsp; io:format("Must be at least 1 process~n", []),<br>&nbsp;&nbsp;&nbsp; 0.0;<br>run(N, M) -&gt;<br>&nbsp;&nbsp;&nbsp; statistics(wall_clock),<br>&nbsp;&nbsp;&nbsp; Limit=N-N*M+1+M,<br>&nbsp;&nbsp;&nbsp; Pid = setup(N-1,Limit,self()),<br><br>&nbsp;&nbsp;&nbsp; {_,T1} = statistics(wall_clock),<br>&nbsp;&nbsp;&nbsp; io:format("Setup : ~w s", [T1/1000]),<br>&nbsp;&nbsp;&nbsp; case N of<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 -&gt; io:format(" (0 spawns)~n", []);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _ -&gt; io:format(" (~w us per spawn) (~w spawns)~n",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [1000*T1/(N-1), N-1])<br>&nbsp;&nbsp;&nbsp; end,<br>&nbsp;&nbsp;&nbsp; statistics(wall_clock),<br>&nbsp; %&nbsp; io:format("run's Pid=~w~n",[Pid]),<br>&nbsp;&nbsp;&nbsp; Pid ! M,<br>&nbsp;&nbsp;&nbsp; K = process(Pid,Limit),<br>&nbsp; %&nbsp; io:format("run's K=~w~n",[K]),<br><br>&nbsp;&nbsp;&nbsp; {_,T2} = statistics(wall_clock),<br>&nbsp;&nbsp;&nbsp; Time = 1000*T2/(M+K),<br>&nbsp;&nbsp;&nbsp; io:format("Run&nbsp;&nbsp; : ~w s (~w us per msg) (~w msgs)~n",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [T2/1000, Time, (M+K)]),<br>&nbsp;T2/1000.<br><br>setup(0,Limit, OldPid) -&gt;<br>&nbsp;&nbsp;&nbsp; OldPid;<br>setup(N,Limit, OldPid) -&gt;<br>&nbsp;&nbsp;&nbsp; NewPid = spawn(?MODULE, process, [OldPid,Limit]),<br>&nbsp;&nbsp;&nbsp; setup(N-1, Limit,NewPid).<br><br><br>process(Pid,Limit) -&gt;<br>&nbsp;&nbsp;&nbsp; receive<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; M -&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Pid ! M-1,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %&nbsp;&nbsp; io:format("from ~w to ~w and M=~w~n",[self(),Pid,M]),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; M &lt;Limit&nbsp; -&gt; -M;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true&nbsp;&nbsp; -&gt; process(Pid,Limit)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<br>&nbsp;&nbsp;&nbsp; end.<br>修改之后，执行zog:run(3000,1000），也就是3000个进程，1000次消息循环，总共300万次消息传递，<span style="font-weight: bold;">结果在2.5秒左右，这也是相当惊人的结果</span>。有人用haskell和scheme各实现了一个版本，有兴趣的看看<a  href="http://haskell.g.hatena.ne.jp/jmk/20070509/1178703858">这里</a>和<a  href="http://jaortega.wordpress.com/2007/05/14/erlang-termite-and-a-blog/">这里</a><br>
<br>
<br><img src ="http://www.blogjava.net/killme2008/aggbug/134417.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-08-04 17:46 <a href="http://www.blogjava.net/killme2008/archive/2007/08/04/134417.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang入门（五）——补遗</title><link>http://www.blogjava.net/killme2008/archive/2007/07/24/132011.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 24 Jul 2007 03:23:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/07/24/132011.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/132011.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/07/24/132011.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/132011.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/132011.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 暂时搞不到《Programming <a title="" href="http://www.erlang.org/">Erlang</a>》，最近就一直在看Erlang自带的例子和Reference Manual。基础语法方面有一些过去遗漏或者没有注意的，断断续续仅记于此。<br><br><span style="font-weight: bold;">1。Erlang的保留字</span>有：<br>
<p>after and andalso band begin bnot bor bsl bsr bxor case catch cond div end
fun if let not of or orelse query receive rem try when xor<a name="1.6"><!-- Empty --></a> </p>
基本都是些用于逻辑运算、位运算以及特殊表达式的符号<br><br><span style="font-weight: bold;">2.Erlang的类型</span>，除了在前面入门一提到的类型外，还包括：<br>1)Binary，用于表示某段未知类型的内存区域<br>比如：<br>1&gt; <strong> &lt;&lt;10,20&gt;&gt;.</strong>
<br>&lt;&lt;10,20&gt;&gt;
<br>2&gt; <strong> &lt;&lt;"ABC"&gt;&gt;.</strong><br>&nbsp;&lt;&lt;65,66,67&gt;&gt;
<br><br>2）Reference，通过调用mk_ref/0产生的运行时的unique term<br><br>3)String，字符串，Erlang中的字符串用双引号包括起来，其实也是list。编译时期，两个邻近的字符串将被连接起来，比如"string" "42" 等价于 "string42"<br><br>4)Record，记录类型，与c语言中的struct类似，模块可以通过-record属性声明，比如：<br>-module(person).
<br>-export([new/2]).<br>-record(person, {name, age}).
<br>new(Name, Age) -&gt;<br>&nbsp; &nbsp;&nbsp; #person{name=Name, age=Age}.
<br>1&gt; <strong> person:new(dennis, 44).</strong>
<br>{person,dennis,44}
<br>&nbsp;在编译后其实已经被转化为tuple。可以通过Name#person.name来访问Name Record的name属性。<br><br><span style="font-weight: bold;">3.模块的预定义属性</span>：<br><code>-module(Module).</code>&nbsp;&nbsp;&nbsp;
声明模块名称，必须与文件名相同<br><code>-export(Functions).</code>&nbsp;&nbsp;
指定向外界导出的函数列表<br><code>-import(Module,Functions).</code>&nbsp;&nbsp;
引入函数，引入的函数可以被当作本地定义的函数使用<br><code>-compile(Options).</code>&nbsp;&nbsp;&nbsp;&nbsp;
设置编译选项，比如export_all<br>-vsn(Vsn).&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 模块版本，设置了此项，可以通过<code>beam_lib:version/1</code>
获取此项信息<br>可以通过-include和-include_lib来包含文件，两者的区别是include-lib不能通过绝对路径查找文件，而是在你当前Erlang的lib目录进行查找。<br><br><span style="font-weight: bold;">4.try表达式</span>，try表达式可以与catch结合使用，比如：<br>
<pre>try Expr<br>catch<br>    throw:Term -&gt; Term;<br>    exit:Reason -&gt; {'EXIT',Reason}<br>    error:Reason -&gt; {'EXIT',{Reason,erlang:get_stacktrace()}}<br>end<br><br>不仅如此，try还可以与after结合使用，类似java中的try..finally，用于进行清除作用，比如：<br>termize_file(Name) -&gt;
{ok,F} = file:open(Name, [read,binary]),
try
{ok,Bin} = file:read(F, 1024*1024),
binary_to_term(Bin)
after
file:close(F)
end.
<br><br><span style="font-weight: bold;">5.列表推断</span>（List Comprehensions），函数式语言特性之一，Erlang中的语法类似：<br>[Expr || Qualifier1,...,QualifierN]
Expr可以是任意的表达式，而Qualifier是generator或者filter。还是各举例子说明下。<br>1&gt; <strong> [X*2 || X &lt;- [1,2,3]].</strong>
[2,4,6]<br><br>2&gt; L=[1,2,3,4,5,6,7].<br>[1,2,3,4,5,6,7]<br>
<pre>3&gt; <span style="font-weight: bold;">[X|X&lt;-L,X&gt;=3].<br>[</span>3,4,5,6,7]<br><br>再看几个比较酷的例子，来自Programming <a title="" href="http://www.erlang.org/">Erlang</a>，<br>比如<span style="font-weight: bold;">快速排序</span>：<br>-module(qsort).<br>-export([qsort/1]).<br>qsort([])-&gt;[];<br>qsort([Pivot|T])-&gt;<br>&nbsp; qsort([X||X&lt;-T,X&lt;Pivot])<br>&nbsp;&nbsp; ++ [Pivot] ++ <br>&nbsp; qsort([X||X&lt;-T,X&gt;=Pivot]).<br><br>搜索<span style="font-weight: bold;">勾股数组</span>：<br>%勾股数组<br>-module(pythag).<br>-export([pythag/1]).<br>pythag(N)-&gt;<br>&nbsp;&nbsp;&nbsp; L=lists:seq(1,N),<br>&nbsp;&nbsp;&nbsp; Square=fun(X) when is_number(X)-&gt;X*X end,<br>&nbsp;&nbsp;&nbsp; [{A,B,C}||<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A&lt;-L,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B&lt;-L,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C&lt;-L,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A+B+C=&lt;N,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Square(A)+Square(B)=:=Square(C)].<br>列表推断将大大减少你的敲击键盘的次数。<br>	&nbsp;<br><span style="font-weight: bold;">6.宏</span>，定义常量或者函数等等，语法如下：<br>-define(Const, Replacement).
-define(Func(Var1,...,VarN), Replacement).
<br>使用的时候在宏名前加个问号？，比如?Const，Replacement将插入宏出现的位置。系统预定义了一些宏:<br><code><span style="font-weight: bold;">?MODULE </span>  表示当前模块名<br><br><span style="font-weight: bold;">?MODULE_STRING</span> 同上，但是以字符串形式<br></code><span style="font-weight: bold;">?FILE</span>    当前模块的文件名<br><span style="font-weight: bold;">?LINE</span>    调用的当前代码行数<br><span style="font-weight: bold;">?MACHINE</span>  机器名<br><br>Erlang的宏与C语言的宏很相似，同样有宏指示符，包括：<br><dl><dt><code>-undef(Macro).</code>
</dt><dd>取消宏定义
</dd><dt><code>-ifdef(Macro).</code>
</dt><dd>当宏Macro有定义的时候，执行以下代码
</dd><dt><code>-ifndef(Macro).</code>
</dt><dd>同上，反之
</dd><dt><code>-else.</code>
</dt><dd>接在ifdef或者ifndef之后，表示不满足前者条件时执行以下代码
<br></dd><dt><code>-endif.</code>
</dt><dd>if终止符</dd></dl>假设宏-define(Square(X),X*X).用于计算平方，那么??X将返回X表达式的字符串形式，类似C语言中#arg<br><br>一个简单的宏例子：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">-</span><span style="color: #000000;">module(macros_demo).<br></span><span style="color: #000000;">-</span><span style="color: #000000;">ifdef(debug).<br></span><span style="color: #000000;">-</span><span style="color: #000000;">define(LOG(X),&nbsp;io:format(</span><span style="color: #800000;">"</span><span style="color: #800000;">{~p,~p}:&nbsp;~p~n</span><span style="color: #800000;">"</span><span style="color: #000000;">,&nbsp;[?MODULE,?LINE,X])).<br></span><span style="color: #000000;">-</span><span style="color: #0000ff;">else</span><span style="color: #000000;">.<br></span><span style="color: #000000;">-</span><span style="color: #000000;">define(LOG(X),&nbsp;true).<br></span><span style="color: #000000;">-</span><span style="color: #000000;">endif.<br></span><span style="color: #000000;">-</span><span style="color: #000000;">define(Square(X),X</span><span style="color: #000000;">*</span><span style="color: #000000;">X).<br></span><span style="color: #000000;">-</span><span style="color: #000000;">compile(export_all).<br>test()</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;A</span><span style="color: #000000;">=</span><span style="color: #000000;">3</span><span style="color: #000000;">,<br>&nbsp;&nbsp;&nbsp;&nbsp;?LOG(A),<br>&nbsp;&nbsp;&nbsp;&nbsp;B</span><span style="color: #000000;">=</span><span style="color: #000000;">?Square(A),<br>&nbsp;&nbsp;&nbsp;&nbsp;io:format(</span><span style="color: #800000;">"</span><span style="color: #800000;">square(~w)&nbsp;is&nbsp;~w~n</span><span style="color: #800000;">"</span><span style="color: #000000;">,[A,B]).</span></div>
当编译时不开启debug选项的时候：<br>17&gt; c(macros_demo).<br>{ok,macros_demo}<br>18&gt; macros_demo:test().<br>square(3) is 9<br><br>当编译时开启debug之后：<br><br>19&gt; c(macros_demo,{d,debug}).<br>{ok,macros_demo}<br>20&gt; macros_demo:test().<br><span style="font-weight: bold;">{macros_demo,11}: 3</span><br>square(3) is 9<br>ok<br><br>可以看到LOG的输出了，行数、模块名以及参数<br>
7、<span style="font-weight: bold;">Process Dictionary</span>，每个进程都有自己的process dictionary，用于存储这个进程内的全局变量，可以通过下列<br>BIFs操作：<br>put(Key, Value)<br>get(Key)<br>get()<br>get_keys(Value)<br>erase(Key)<br>erase()<br><br><span style="font-weight: bold;">8、关于分布式编程</span>，需要补充的几点<br>1）节点之间的连接默认是transitive，也就是当节点A连接了节点B，节点B连接了节点C，那么节点A也与节点C互相连接<br>可以通过启动节点时指定参数-connect_all false来取消默认行为<br><br>2）隐藏节点，某些情况下，你希望连接一个节点而不去连接其他节点，你可以通过在节点启动时指定-hidden选项<br>来启动一个hidden node。在此情况下，通过nodes()查看所有连接的节点将不会出现隐藏的节点，想看到隐藏的节点<br>可以通过nodes(hidden)或者nodes(connected)来查看。<br><br>完整的erl选项如下：<br>
<table border="1" cellpadding="2" cellspacing="0">
    <tbody>
        <tr>
            <td align="left" valign="center"><code>-connect_all false</code> </td>
            <td align="left" valign="center">上面已经解释。
            </td>
        </tr>
        <tr>
            <td align="left" valign="center"><code>-hidden</code> </td>
            <td align="left" valign="center">启动一个hidden node<br> </td>
        </tr>
        <tr>
            <td align="left" valign="center"><code>-name Name</code> </td>
            <td align="left" valign="center">启动一个系统成为节点，使用long name. </td>
        </tr>
        <tr>
            <td align="left" valign="center"><code>-setcookie Cookie</code> </td>
            <td align="left" valign="center">与<code><a title="" href="http://www.erlang.org/">Erlang</a>:set_cookie(node(),
            Cookie)</code>.相同，设置magic cookie<br> </td>
        </tr>
        <tr>
            <td align="left" valign="center"><code>-sname Name</code> </td>
            <td align="left" valign="center">启动一个Erlang系统作为节点，使用short name <br></td>
        </tr>
    </tbody>
</table>
<br>注意,<span style="font-weight: bold;">short name启动的节点是无法与long name节点通信的</span>。<br><br><span style="font-weight: bold;">9.一个小细节，在Erlang中小于等于是用=&lt;表示，而不是一般语言中的&lt;=语法，我犯过错误的地方，同样，不等于都是用/号，而不是</span><br style="font-weight: bold;"><span style="font-weight: bold;">!,比如/=、=/=。</span><br><br><span style="font-weight: bold;">10.and or 和andalso orelse的区别</span><br><br>and和or会计算两边的表达式，而andalso和orelse的求值采用短路机制，比如exp1 andalso exp2，当exp1返回false之后，就不会去求值<br>exp2，而是直接返回false，而exp1 and exp2会对exp1和exp2都进行求值，or与orelse也类似。<br>&nbsp;<br>今天在<a href="http://www.erlang-china.org/">erlang-china</a>下到了《Programming <a title="" href="http://www.erlang.org/">Erlang</a>》，准备打印一份看看，进入OTP的学习。 &nbsp;<br><br></pre>
<br>&nbsp; <br>&nbsp;
<br></pre>
<br><br><br><br><br><img src ="http://www.blogjava.net/killme2008/aggbug/132011.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-07-24 11:23 <a href="http://www.blogjava.net/killme2008/archive/2007/07/24/132011.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从一个小例子出发之ruby、scheme和Erlang的简单比较</title><link>http://www.blogjava.net/killme2008/archive/2007/07/15/130384.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 15 Jul 2007 08:11:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/07/15/130384.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/130384.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/07/15/130384.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/130384.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/130384.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; Lich Ray写了个帖子《<a href="http://www.javaeye.com/post/333938">函数式编程语言曲高和寡？</a>》，用快速排序的例子来说明函数式编程在表达思想方面比命令式语言更容易，其实这一点毋庸置疑，如果你正在读或者读过SICP的话。文中给了haskell、scheme和javascript的实现例子，我也凑趣写了个Erlang版本，haskell我不了解就不说了，其他实现分别如下：<br>scheme：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">(define&nbsp;(qsort&nbsp;ls)&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(null</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;ls)&nbsp;</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">()&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((x&nbsp;(car&nbsp;ls))&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(xs&nbsp;(cdr&nbsp;ls)))&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((lt&nbsp;(filter&nbsp;(lambda&nbsp;(y)&nbsp;(&lt;&nbsp;y&nbsp;x))&nbsp;xs))&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(st&nbsp;(filter&nbsp;(lambda&nbsp;(y)&nbsp;(&gt;=&nbsp;y&nbsp;x))&nbsp;xs)))&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(append&nbsp;(qsort&nbsp;lt)&nbsp;(list&nbsp;x)&nbsp;(qsort&nbsp;st))))))&nbsp;&nbsp;</span></div>
<br>javascript:<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">//</span><span style="color: #000000;">&nbsp;把要用到的表达式抽象出来&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;Array</span><span style="color: #000000;">.</span><span style="color: #0000ff;">prototype</span><span style="color: #000000;">.</span><span style="color: #000000;">head&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;function&nbsp;()&nbsp;{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;this[</span><span style="color: #800000;">0</span><span style="color: #000000;">];&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;Array</span><span style="color: #000000;">.</span><span style="color: #0000ff;">prototype</span><span style="color: #000000;">.</span><span style="color: #000000;">tail&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;function&nbsp;()&nbsp;{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;this</span><span style="color: #000000;">.</span><span style="color: #000000;">slice(</span><span style="color: #800000;">1</span><span style="color: #000000;">);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;Array</span><span style="color: #000000;">.</span><span style="color: #0000ff;">prototype</span><span style="color: #000000;">.</span><span style="color: #000000;">filter&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;function&nbsp;(proc)&nbsp;{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;tmpArr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[];&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(var&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;this</span><span style="color: #000000;">.</span><span style="color: #0000ff;">length</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(proc(this[i])&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;true)&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tmpArr</span><span style="color: #000000;">.</span><span style="color: #0000ff;">push</span><span style="color: #000000;">(this[i]);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;tmpArr;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;Array</span><span style="color: #000000;">.</span><span style="color: #0000ff;">prototype</span><span style="color: #000000;">.</span><span style="color: #000000;">qsort&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;function&nbsp;()&nbsp;{&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(this&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;false)&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;[]&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;x</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;xs</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;lt</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;st&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;this</span><span style="color: #000000;">.</span><span style="color: #000000;">head()&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xs&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;this</span><span style="color: #000000;">.</span><span style="color: #000000;">tail()&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lt&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;xs</span><span style="color: #000000;">.</span><span style="color: #000000;">filter(function&nbsp;(y)&nbsp;{</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;y&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;x})&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;st&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;xs</span><span style="color: #000000;">.</span><span style="color: #000000;">filter(function&nbsp;(y)&nbsp;{</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;y&nbsp;</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">&nbsp;x})&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;lt</span><span style="color: #000000;">.</span><span style="color: #000000;">qsort()</span><span style="color: #000000;">.</span><span style="color: #000000;">concat([x]</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;st</span><span style="color: #000000;">.</span><span style="color: #000000;">qsort())&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></div>
用Erlang的话，Erlang的list其实跟scheme的list是一样的，甚至连定义的基本高阶函数都一样：map,filter，append等等,利用lists模块提供的filter和append，我们可以写出：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;qsort([])</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">[];&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;qsort([H</span><span style="color: #000000;">|</span><span style="color: #000000;">T])</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Lt</span><span style="color: #000000;">=</span><span style="color: #000000;">lists</span><span style="color: #000000;">:</span><span style="color: #000000;">filter(fun(E)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">E</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">H&nbsp;end</span><span style="color: #000000;">,</span><span style="color: #000000;">T)</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;St</span><span style="color: #000000;">=</span><span style="color: #000000;">lists</span><span style="color: #000000;">:</span><span style="color: #000000;">filter(fun(E)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">E</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">H&nbsp;end</span><span style="color: #000000;">,</span><span style="color: #000000;">T)</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;lists</span><span style="color: #000000;">:</span><span style="color: #000000;">append(qsort(Lt)</span><span style="color: #000000;">,</span><span style="color: #000000;">lists</span><span style="color: #000000;">:</span><span style="color: #000000;">append([H]</span><span style="color: #000000;">,</span><span style="color: #000000;">qsort(St)))</span><span style="color: #000000;">.</span><span style="color: #000000;">&nbsp;&nbsp;</span></div>
&nbsp; &nbsp; 我们来比较下scheme和Erlang版本，两者最显著的不同是，scheme使用了条件语句if，而Erlang却是通过模式匹配来代替条件分支判断。同样，在list的分解上面，Erlang也是利用了规则匹配来代替car,cdr函数，从这里可以看出规则匹配在Erlang中的主要作用：分解复杂数据结构以便赋值和条件分支的分派。<br>&nbsp;&nbsp;&nbsp; 扯远些可以谈到模式匹配是以&#8220;like-a&#8221;来代替消息分派在传统命令式语言中严格的&#8220;is-a&#8221;，这也跟现实世界的情况更为符合，现实世界中我们对事物的判断都是模糊。而这一点，不正是&#8220;Duck-Typing&#8221;？传统语言对于对象的类型(type)判断来源于严格确定对象是什么类（class），不是这个类它就没有相应的方法，而事实上类与类型这两个概念并不是一致的，对象的类型更应该根据对象能够做什么来决定。扯远了，这只是我读《<a href="http://www.javaeye.com/topic/25649">失踪的链环</a>》得来的感受，如果对模式匹配还有怀疑的话，让我们回到这个例子的Erlang版本，代码中我们调用了两次filter进行全表扫描，以便得到根据H切割的大小两个部分，这在性能上有不小的影响，那么我们能不能只进行一次全表扫描呢，返回结果是&#8220;大小&#8221;两个部分，看看Erlang应该怎么写：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;"></span><span style="color: #000000;"></span><span style="color: #000000;"></span><span style="color: #0000ff;">sort([]) -&gt; [];<br>sort([Pivot|Rest]) -&gt;<br>&nbsp;&nbsp; {Smaller, Bigger} = split(Pivot, Rest),<br>&nbsp;&nbsp; lists:append(sort(Smaller), [Pivot|sort(Bigger)]).
<br>split</span><span style="color: #000000;">(Pivot</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;L)&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">split</span><span style="color: #000000;">(Pivot</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;L</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[]</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[])</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">split</span><span style="color: #000000;">(Pivot</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[]</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Smaller</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Bigger)&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>{Smaller</span><span style="color: #000000;">,</span><span style="color: #000000;">Bigger};<br></span><span style="color: #0000ff;">split</span><span style="color: #000000;">(Pivot</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[H</span><span style="color: #000000;">|</span><span style="color: #000000;">T]</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Smaller</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Bigger)&nbsp;when&nbsp;H&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;Pivot&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">split</span><span style="color: #000000;">(Pivot</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;T</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[H</span><span style="color: #000000;">|</span><span style="color: #000000;">Smaller]</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Bigger);<br></span><span style="color: #0000ff;">split</span><span style="color: #000000;">(Pivot</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[H</span><span style="color: #000000;">|</span><span style="color: #000000;">T]</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Smaller</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Bigger)&nbsp;when&nbsp;H&nbsp;</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">&nbsp;Pivot&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">split</span><span style="color: #000000;">(Pivot</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;T</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Smaller</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[H</span><span style="color: #000000;">|</span><span style="color: #000000;">Bigger])</span><span style="color: #000000;">.</span></div>
<br>&nbsp;&nbsp;&nbsp; 这几行代码充分展现了模式匹配的威力，不过Erlang其实有内置的方法partition用于切割list的，这里只是为了展现模式匹配，因此上面的代码可以改为：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">sort</span><span style="color: #000000;">([])&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;[];<br></span><span style="color: #0000ff;">sort</span><span style="color: #000000;">([Pivot</span><span style="color: #000000;">|</span><span style="color: #000000;">Rest])&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>{Smaller</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Bigger}&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;lists</span><span style="color: #000000;">:</span><span style="color: #000000;">partition(fun(E)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">E</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Pivot&nbsp;end</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Rest)</span><span style="color: #000000;">,</span><span style="color: #000000;"><br>lists</span><span style="color: #000000;">:</span><span style="color: #000000;">append(</span><span style="color: #0000ff;">sort</span><span style="color: #000000;">(Smaller)</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[Pivot</span><span style="color: #000000;">|</span><span style="color: #0000ff;">sort</span><span style="color: #000000;">(Bigger)])</span><span style="color: #000000;">.</span></div>
<br>同样的代码改写为ruby版本：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">def&nbsp;qsort(array)<br>&nbsp; arr=array.dup<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;arr</span><span style="color: #000000;">==</span><span style="color: #000000;">[]<br>&nbsp;&nbsp;&nbsp;&nbsp;[]<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;x</span><span style="color: #000000;">=</span><span style="color: #000000;">arr</span><span style="color: #000000;">.</span><span style="color: #0000ff;">shift</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;smaller</span><span style="color: #000000;">,</span><span style="color: #000000;">bigger</span><span style="color: #000000;">=</span><span style="color: #000000;">arr</span><span style="color: #000000;">.</span><span style="color: #000000;">partition{</span><span style="color: #000000;">|</span><span style="color: #000000;">e</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;e</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">x}<br>&nbsp;&nbsp;&nbsp;&nbsp;qsort(smaller)</span><span style="color: #000000;">+</span><span style="color: #000000;">[x]</span><span style="color: #000000;">+</span><span style="color: #000000;">qsort(bigger)<br>&nbsp;&nbsp;end<br>end</span></div>
&nbsp;&nbsp;&nbsp; ruby与Erlang都有并行赋值，但是ruby不支持模式匹配。请注意ruby并没有尾递归优化，因此上面的代码在数组比较大的时候会导致栈溢出，想用ruby做函数式编程应该尽量多使用循环和map,filter,collect等辅助高阶函数。<br>&nbsp;&nbsp;&nbsp; 另外一个Erlang与ruby、scheme比较重要的区别是Erlang的变量只能赋值一次（或者说绑定），也就是single assignment。这个特点与Erlang所要满足的运行场景有紧密关系，当系统发生错误时，就可以从原来的值重新启动任务，而不用担心由于变量值的变化导致系统恢复困难。<br><br><br><br><br><img src ="http://www.blogjava.net/killme2008/aggbug/130384.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-07-15 16:11 <a href="http://www.blogjava.net/killme2008/archive/2007/07/15/130384.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang分布式在linux和windows上的注意事项</title><link>http://www.blogjava.net/killme2008/archive/2007/06/29/127099.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 29 Jun 2007 08:33:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/06/29/127099.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/127099.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/06/29/127099.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/127099.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/127099.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 没事做，就在两台机器间测试下Erlang分布式的例子，一个台是windowsXP，一台装的redHat9，没有详细的文档，自己摸索着搞成功了，记录下。<br><br>1.首先,分布式Erlang的实现提供了自有的安全机制来预防未经授权的Erlang系统访问。Erlang系统与别的机器进行交互时必须有同样的magic cookie,保存在一个称为.erlang.cookie的文件中，为了在两台不同机器间测试，需要编辑一份.erlang.cookie,内容随便，比如：<br>just_test<br><br>然后将这份文件拷贝到windows环境变量HOMEPATH所在的目录
，比如我的是C:\Documents and Settings\Admin，而linux拷贝到环境变量$HOME指向的目录，比如我这里是/root。特别注意一点，linux的.erlang.cookie文件需要设置权限为-r--------，也就是400，仅所有者可读：<br>chmod 400 .erlang.cookie<br><br>2.因为Erlang中的node名称是name@host，host是计算机名，因此在两台机器上都需要将计算机名和ip加进hosts文件，这个文件在linux下是在/etc/hosts，你可以用vi编辑如下：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">127.0</span><span style="color: #000000;">.</span><span style="color: #000000;">0.1</span><span style="color: #000000;">&nbsp;&nbsp;localhost&nbsp;localhost<br>x.x.x.x&nbsp;&nbsp;&nbsp;&nbsp;zane&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zane</span><span style="color: #008000;">&nbsp;&nbsp; #</span><span style="color: #008000;">windows机器的ip和计算机名</span></div>
，hosts在windows系统的C:\WINDOWS\system32\drivers\etc目录下，编辑：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">127.0</span><span style="color: #000000;">.</span><span style="color: #000000;">0.1</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;localhost<br>x.x.x.x&nbsp;&nbsp;&nbsp;dennis&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">linux机器的名称和ip</span></div>
<br>3.第三步，要启动节点，通过命令erl -sname 或者erl -name，在此之前需要启动epmd进程，它负责映射符号名到机器地址<br>在两个机器都执行：<br>epmd -daemon<br><br>4.至此配置完成，可以测试下Erlang分布式编程在不同的机器和系统之间了（比如《<a  href="http://www.blogjava.net/killme2008/archive/2007/06/15/124547.html">Erlang入门(三)--分布式编程</a>》中的ping pong例子），very cool!<br><br><img src ="http://www.blogjava.net/killme2008/aggbug/127099.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-06-29 16:33 <a href="http://www.blogjava.net/killme2008/archive/2007/06/29/127099.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang入门（四）——错误处理和鲁棒性</title><link>http://www.blogjava.net/killme2008/archive/2007/06/25/126156.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 25 Jun 2007 09:10:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/06/25/126156.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/126156.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/06/25/126156.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/126156.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/126156.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;&nbsp; 去了趟福州，事情没搞定，托给同学帮忙处理了，回家休息了两天就来上班了。回家这几天最大的收获是第四次重读《深入Java虚拟机》，以前不大明了的章节豁然开朗，有种开窍的感觉，水到渠成，看来技术的学习还是急不来。&nbsp;&nbsp;&nbsp; 闲话不提，继续Erlang的学习，上次学习到分布式编程的章节，剩下三章分别是错误处理、构造健壮的系统和杂项，错误处理和...&nbsp;&nbsp;<a href='http://www.blogjava.net/killme2008/archive/2007/06/25/126156.html'>阅读全文</a><img src ="http://www.blogjava.net/killme2008/aggbug/126156.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-06-25 17:10 <a href="http://www.blogjava.net/killme2008/archive/2007/06/25/126156.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang入门（三）——分布式编程</title><link>http://www.blogjava.net/killme2008/archive/2007/06/15/124547.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 15 Jun 2007 09:33:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/06/15/124547.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/124547.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/06/15/124547.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/124547.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/124547.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 明天要回家一个星期了，好好休息下。今天找到别人翻译的<a href="http://computebank.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&amp;_c=BlogPart&amp;_c02_owner=1&amp;partqs=cat%3d%25e5%2588%2586%25e5%25b8%2583%25e5%25bc%258f%25e5%25b9%25b6%25e8%25a1%258c%25e8%25ae%25a1%25e7%25ae%2597">Erlang编程手册</a>，值的好好读一遍。<br />
&nbsp;&nbsp;&nbsp; 所谓分布式的Erlang应用是运行在一系列Erlang节点组成的网络之上。这样的系统的性质与单一节点上的Erlang系统并没有什么不同。分布式这是个&#8220;大词&#8221;，Erlang从语言原生角度支持分布式编程，相比于java简单不少。<br />
一、分布式机制<br />
下列的BIFs是用于分布式编程：<br />
<span style="font-weight: bold;">spawn(Node, Mod, Func, Args)</span><br />
启动远程节点的一个进程<br />
<br />
<span style="font-weight: bold;">spawn_link(Node, Mod, Func, Args)</span><br />
启动远程节点的一个进程并创建连接到该进程<br />
<br />
<span style="font-weight: bold;">monitor_node(Node, Flag)</span><br />
如果Flag是true,这个函数将使调用（该函数）的进程可以监控节点Node。如果节点已经舍弃或者并不存在，调用的进程将收到一个{nodedown,Node}的消息。如果Flag是false,监控将被关闭<br />
<br />
<span style="font-weight: bold;">node()</span><br />
返回我们自己的进程name<br />
<br />
<span style="font-weight: bold;">nodes()</span><br />
返回其他已知的节点name列表<br />
<br />
<span style="font-weight: bold;">node(Item)</span><br />
返回原来Item的节点名称，Item可以是Pid,引用（reference）或者端口(port)<br />
<br />
<span style="font-weight: bold;">disconnect_node(Nodename)</span><br />
从节点Nodename断开。<br />
<br />
&nbsp; &nbsp; 节点是分布式Erlang的核心概念。在一个分布式Erlang应用中，术语（term)节点(node）意味着一个可以加入分布式transactions的运行系统。通过一个称为net kernal的特殊进程，一个独立的Erlang系统可以成为一个分布式Erlang系统的一部分。当net kernal进程启动的时候，我们称系统是alive的。<br />
<br />
&nbsp; &nbsp; 与远程节点上的进程进行通信，与同一节点内的进程通信只有一点不同：<br />
&nbsp;&nbsp;
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp; {Name</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;Node}&nbsp;</span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 0);">&nbsp;Mess</span><span style="color: rgb(0, 0, 0);">.</span></div>
显然，需要接收方增加一个参数Node用于指定接受进程所在的节点。节点的name一般是用@隔开的atom类型，比如pong@dennis，表示计算机名为dennis上的pong节点。通过执行:<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">erl&nbsp;</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">sname&nbsp;pong</span></div>
将在执行的计算机中创建一个节点pong。为了运行下面的例子，你可能需要两台计算机，如果只有一台，只要同时开两个Erlang系统并以不同的节点名称运行也可以。<br />
<br />
二、一些例子。<br />
&nbsp;&nbsp;&nbsp; 这个例子完全来自上面提到的翻译的连接，关于分布式编程的章节。我增加了截图和说明。<br />
首先是代码：<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">module(tut17)</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);"><br />
<br />
</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">export([start_ping</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(128, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;start_pong</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(128, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;ping</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(128, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;pong</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(128, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">])</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);"><br />
<br />
ping(</span><span style="color: rgb(128, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;Pong_Node)&nbsp;</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;{pong</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;Pong_Node}&nbsp;</span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 0);">&nbsp;finished</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;io</span><span style="color: rgb(0, 0, 0);">:</span><span style="color: rgb(0, 0, 255);">format</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0); font-weight: bold;">"</span><span style="color: rgb(0, 0, 0); font-weight: bold;">ping&nbsp;finished~n</span><span style="color: rgb(0, 0, 0); font-weight: bold;">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;[]);<br />
<br />
ping(N</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;Pong_Node)&nbsp;</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;{pong</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;Pong_Node}&nbsp;</span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 0);">&nbsp;{ping</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;self()}</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;receive<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pong&nbsp;</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;io</span><span style="color: rgb(0, 0, 0);">:</span><span style="color: rgb(0, 0, 255);">format</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0); font-weight: bold;">"</span><span style="color: rgb(0, 0, 0); font-weight: bold;">Ping&nbsp;received&nbsp;pong~n</span><span style="color: rgb(0, 0, 0); font-weight: bold;">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;[])<br />
&nbsp;&nbsp;&nbsp;&nbsp;end</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;ping(N&nbsp;</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(128, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;Pong_Node)</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);"><br />
<br />
pong()&nbsp;</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;receive<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;finished&nbsp;</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;io</span><span style="color: rgb(0, 0, 0);">:</span><span style="color: rgb(0, 0, 255);">format</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0); font-weight: bold;">"</span><span style="color: rgb(0, 0, 0); font-weight: bold;">Pong&nbsp;finished~n</span><span style="color: rgb(0, 0, 0); font-weight: bold;">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;[]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ping</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;Ping_PID}&nbsp;</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;io</span><span style="color: rgb(0, 0, 0);">:</span><span style="color: rgb(0, 0, 255);">format</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0); font-weight: bold;">"</span><span style="color: rgb(0, 0, 0); font-weight: bold;">Pong&nbsp;received&nbsp;ping~n</span><span style="color: rgb(0, 0, 0); font-weight: bold;">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;[])</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ping_PID&nbsp;</span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 0);">&nbsp;pong</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pong()<br />
&nbsp;&nbsp;&nbsp;&nbsp;end</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);"><br />
<br />
start_pong()&nbsp;</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;register(pong</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;spawn(tut17</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;pong</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;[]))</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);"><br />
<br />
start_ping(Pong_Node)&nbsp;</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;spawn(tut17</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;ping</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;[</span><span style="color: rgb(128, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;Pong_Node])</span><span style="color: rgb(0, 0, 0);">.</span></div>
<br />
&nbsp;&nbsp;&nbsp; 代码是创建两个相互通信的进程，相互发送消息并通过io显示在屏幕上，本来是一个单一系统的例子，现在我们让两个进程运行在不同的两个节点上。注意start_ping方法，创建的进程调用ping方法，ping方法有两个参数，一个是发送消息的次数，一个就是远程节点的name了，也就是我们将要创建的进程pong的所在节点。start_pong创建一个调用函数pong的进程，并注册为名字pong（因此在ping方法中可以直接发送消息给pong)。<br />
&nbsp;&nbsp;&nbsp; 我是在windows机器上测试，首先打开两个cmd窗口，并cd到Erlang的安装目录下的bin目录，比如C:\Program Files\erl5.5.3\bin,将上面的程序存为tut17.erl，并拷贝到同一个目录下。我们将创建两个节点，一个叫ping@dennis,一个叫pong@dennis,其中dennis是我的机器名。见下图：<br />
<img src="http://www.blogjava.net/images/blogjava_net/killme2008/d-erlang1.jpg" alt="" border="0" /><br />
采用同样的命令<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">erl&nbsp;</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">sname&nbsp;ping</span></div>
创建ping节点。然后在pong节点下执行start_pong()：<br />
<img src="http://www.blogjava.net/images/blogjava_net/killme2008/d-erlang2.jpg" alt="" border="0" /><br />
<br />
OK,这样就在节点pong上启动了pong进程，然后在ping节点调用start_ping，传入参数就是pong@dennis<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">tut17</span><span style="color: rgb(0, 0, 0);">:</span><span style="color: rgb(0, 0, 0);">start_ping(pong</span><span style="color: rgb(128, 0, 128);">@dennis</span><span style="color: rgb(0, 0, 0);">)</span><span style="color: rgb(0, 0, 0);">.</span></div>
执行结果如下图：<br />
<img src="http://www.blogjava.net/images/blogjava_net/killme2008/d-erlang3.jpg" alt="" border="0" /><br />
同样在pong节点上也可以看到：<br />
<img src="http://www.blogjava.net/images/blogjava_net/killme2008/d-erlang4.jpg" alt="" border="0" /><br />
<br />
&nbsp;&nbsp;&nbsp; 结果如我们预期的那样，不同节点上的两个进程相互通信如此简单。我们给模块tut17增加一个方法，用于启动远程进程，也就是调用spawn(Node,Module,Func,Args)方法：<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">start(Ping_Node)&nbsp;</span><span style="color: rgb(0, 0, 0);">-&gt;</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;register(pong</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;spawn(tut17</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;pong</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;[]))</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;spawn(Ping_Node</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;tut17</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;ping</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;[</span><span style="color: rgb(128, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;node()])</span><span style="color: rgb(0, 0, 0);">.</span></div>
pong进程启动Ping_Node节点上的进程ping。具体结果不再给出。<br />
<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;  <br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/124547.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-06-15 17:33 <a href="http://www.blogjava.net/killme2008/archive/2007/06/15/124547.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang入门（二）—并发编程</title><link>http://www.blogjava.net/killme2008/archive/2007/06/14/124355.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 14 Jun 2007 09:12:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/06/14/124355.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/124355.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/06/14/124355.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/124355.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/124355.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; Erlang中的process——进程是轻量级的，并且进程间无共享。查了很多资料，似乎没人说清楚轻量级进程算是什么概念，继续查找中。。。闲话不提，进入并发编程的世界。本文算是学习笔记，也可以说是《Concurrent Programming in ERLANG》第五张的简略翻译。
<br><span style="font-weight: bold;">1.进程的创建</span><br>&nbsp;&nbsp;&nbsp; 进程是一种自包含的、分隔的计算单元，并与其他进程并发运行在系统中，在进程间并没有一个继承体系，当然，应用开发者可以设计这样一个继承体系。<br>&nbsp;&nbsp;&nbsp; 进程的创建使用如下语法：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">Pid&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;spawn(Module</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;FunctionName</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;ArgumentList)</span></div>
<br>spawn接受三个参数：模块名，函数名以及参数列表，并返回一个代表创建的进程的标识符（Pid）。<br>如果在一个已知进程Pid1中执行：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">Pid2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;spawn(Mod</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Func</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Args)</span></div>
那么，Pid2仅仅能被Pid1可见，Erlang系统的安全性就构建在限制进程扩展的基础上。<br><br><span style="font-weight: bold;">2.进程间通信</span><br>&nbsp;&nbsp;&nbsp; Erlang进程间的通信只能通过发送消息来实现，消息的发送使用!符号：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">Pid&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">&nbsp;Message</span></div>
&nbsp;&nbsp;&nbsp; 其中Pid是接受消息的进程标记符，Message就是消息。接受方和消息可以是任何的有效的Erlang结构，只要他们的结果返回的是进程标记符和消息。<br>&nbsp;&nbsp;&nbsp; 消息的接受是使用receive关键字，语法如下：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">receive<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Message1&nbsp;[when&nbsp;Guard1]&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Actions1&nbsp;;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Message2&nbsp;[when&nbsp;Guard2]&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Actions2&nbsp;;<br></span><span style="color: #000000;"><img src="http://www.blogjava.net/Images/dot.gif"></span><span style="color: #000000;"><br>end</span></div>
<br>&nbsp;&nbsp;&nbsp; 每一个Erlang进程都有一个&#8220;邮箱&#8221;，所有发送到进程的消息都按照到达的顺序存储在&#8220;邮箱&#8221;里，上面所示的消息Message1,Message2，当它们与&#8220;邮箱&#8221;里的消息匹配，并且约束（Guard）通过，那么相应的ActionN将执行，并且receive返回的是ActionN的最后一条执行语句的结果。Erlang对&#8220;邮箱&#8221;里的消息匹配是有选择性的，只有匹配的消息将被触发相应的Action，而没有匹配的消息将仍然保留在&#8220;邮箱&#8221;里。这一机制保证了没有消息会阻塞其他消息的到达。<br>&nbsp;&nbsp;&nbsp; 消息到达的顺序并不决定消息的优先级，进程将轮流检查&#8220;邮箱&#8221;里的消息进行尝试匹配。消息的优先级别下文再讲。<br><br>&nbsp;&nbsp;&nbsp; 如何接受特定进程的消息呢？答案很简单，将发送方(sender)也附送在消息当中，接收方通过模式匹配决定是否接受，比如：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">Pid&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">&nbsp;{self()</span><span style="color: #000000;">,</span><span style="color: #000000;">abc}</span></div>
给进程Pid发送消息{self(),abc}，利用self过程得到发送方作为消息发送。然后接收方：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">receive<br>&nbsp; {Pid</span><span style="color: #000000;">1,</span><span style="color: #000000;">Msg}&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br></span><span style="color: #000000;"><img src="http://www.blogjava.net/Images/dot.gif"></span><span style="color: #000000;"><br>end</span></div>
通过模式匹配决定只有Pid1进程发送的消息才接受。<br><br><span style="font-weight: bold;">3.一些例子</span><br>&nbsp;&nbsp;&nbsp; 仅说明下书中计数的进程例子,我添加了简单注释：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">-</span><span style="color: #000000;">module(counter)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #000000;">-</span><span style="color: #000000;">compile(export_all)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #000000;">%</span><span style="color: #000000;">&nbsp;start()，返回一个新进程，进程执行函数loop<br>start()</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">spawn(counter</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;loop</span><span style="color: #000000;">,</span><span style="color: #000000;">[</span><span style="color: #800000;">0</span><span style="color: #000000;">])</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #000000;">%</span><span style="color: #000000;">&nbsp;调用此操作递增计数<br>increment(Counter)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;Counter</span><span style="color: #000000;">!</span><span style="color: #000000;">increament</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #000000;">%</span><span style="color: #000000;">&nbsp;返回当前计数值<br>value(Counter)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;Counter</span><span style="color: #000000;">!</span><span style="color: #000000;">{self()</span><span style="color: #000000;">,</span><span style="color: #000000;">value}</span><span style="color: #000000;">,</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;receive<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{Counter</span><span style="color: #000000;">,</span><span style="color: #000000;">Value}</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #800080;">%返回给调用方</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Value<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>&nbsp;&nbsp;</span><span style="color: #800080;">%停止计数</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;stop(Counter)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Counter</span><span style="color: #000000;">!</span><span style="color: #000000;">{self()</span><span style="color: #000000;">,</span><span style="color: #000000;">stop}</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>&nbsp;loop(Val)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;receive<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #800080;">%接受不同的消息</span><span style="color: #000000;">，决定返回结果<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;increament</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loop(Val</span><span style="color: #000000;">+</span><span style="color: #800000;">1</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{From</span><span style="color: #000000;">,</span><span style="color: #000000;">value}</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;From</span><span style="color: #000000;">!</span><span style="color: #000000;">{self()</span><span style="color: #000000;">,</span><span style="color: #000000;">Val}</span><span style="color: #000000;">,</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loop(Val);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stop</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #800080;">%不是以上3种消息</span><span style="color: #000000;">，就继续等待<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Other</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loop(Val)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end</span><span style="color: #000000;">.</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><br></span></div>
<br>调用方式：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;"></span><span style="color: #000000;"></span><span style="color: #800000;">1</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;Counter1</span><span style="color: #000000;">=</span><span style="color: #000000;">counter</span><span style="color: #000000;">:</span><span style="color: #000000;">start()</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #000000;">&lt;</span><span style="color: #800000;">0.30</span><span style="color: #000000;">.</span><span style="color: #800000;">0</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #800000;">2</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;counter</span><span style="color: #000000;">:</span><span style="color: #000000;">value(Counter1)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #800000;">0</span><span style="color: #000000;"><br></span><span style="color: #800000;">3</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;counter</span><span style="color: #000000;">:</span><span style="color: #000000;">increment(Counter1)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>increament<br></span><span style="color: #800000;">4</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;counter</span><span style="color: #000000;">:</span><span style="color: #000000;">value(Counter1)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #800000;">1</span><span style="color: #000000;"><br></span></div>
<br>基于进程的消息传递机制可以很容易地实现有限状态机（FSM），状态使用函数表示，而事件就是消息。具体不再展开<br><br><span style="font-weight: bold;">4.超时设置</span><br>&nbsp;&nbsp;&nbsp; Erlang中的receive语法可以添加一个额外选项：timeout，类似：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">receive<br>&nbsp;&nbsp;&nbsp;Message1&nbsp;[when&nbsp;Guard1]&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Actions1&nbsp;;<br>&nbsp;&nbsp;&nbsp;Message2&nbsp;[when&nbsp;Guard2]&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Actions2&nbsp;;<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;"><img src="http://www.blogjava.net/Images/dot.gif"></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;after<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TimeOutExpr&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ActionsT<br>end</span></div>
<br>after之后的TimeOutExpr表达式返回一个整数time（毫秒级别），时间的精确程度依赖于Erlang在操作系统或者硬件的实现。如果在time毫秒内，没有一个消息被选中，超时设置将生效，也就是ActionT将执行。time有两个特殊值：<br>1)<span style="font-weight: bold;">infinity</span>(无穷大)，infinity是一个atom，指定了超时设置将永远不会被执行。<br>2) <span style="font-weight: bold;">0</span>，超时如果设定为0意味着超时设置将立刻执行，但是系统将首先尝试当前&#8220;邮箱&#8221;里的消息。<br><br>&nbsp;&nbsp;&nbsp; 超时的常见几个应用，比如挂起当前进程多少毫秒：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">sleep</span><span style="color: #000000;">(</span><span style="color: #0000ff;">Time</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;receive<br>&nbsp;&nbsp;&nbsp;&nbsp;after&nbsp;</span><span style="color: #0000ff;">Time</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;true<br>end</span><span style="color: #000000;">.</span></div>
&nbsp; &nbsp; 比如清空进程的&#8220;邮箱&#8221;,丢弃&#8220;邮箱&#8221;里的所有消息：<br>&nbsp;&nbsp;&nbsp;
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">flush_buffer()&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;receive<br>&nbsp;&nbsp;&nbsp;&nbsp;AnyMessage&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flush_buffer()<br>&nbsp;&nbsp;after&nbsp;</span><span style="color: #800000;">0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;true<br>end</span><span style="color: #000000;">.</span></div>
&nbsp;&nbsp;&nbsp; 将当前进程永远挂起：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp; suspend()&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;receive<br>&nbsp;&nbsp;&nbsp;&nbsp;after<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;infinity&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;true<br>&nbsp;&nbsp;&nbsp;&nbsp;end</span><span style="color: #000000;">.</span></div>
&nbsp;&nbsp;&nbsp; 超时也可以应用于实现定时器，比如下面这个例子，创建一个进程，这个进程将在设定时间后向自己发送消息：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">-</span><span style="color: #000000;">module(timer)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #000000;">-</span><span style="color: #000000;">export([timeout</span><span style="color: #000000;">/</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">cancel</span><span style="color: #000000;">/</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">timer</span><span style="color: #000000;">/</span><span style="color: #800000;">3</span><span style="color: #000000;">])</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>timeout(</span><span style="color: #0000ff;">Time</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Alarm</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;spawn(timer</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;timer</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[self()</span><span style="color: #000000;">,</span><span style="color: #0000ff;">Time</span><span style="color: #000000;">,</span><span style="color: #0000ff;">Alarm</span><span style="color: #000000;">])</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>cancel(Timer)&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;Timer&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">&nbsp;{self()</span><span style="color: #000000;">,</span><span style="color: #000000;">cancel}</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>timer(Pid</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Time</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Alarm</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;receive<br>&nbsp;&nbsp;&nbsp;&nbsp;{Pid</span><span style="color: #000000;">,</span><span style="color: #000000;">cancel}&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;true<br>&nbsp;&nbsp;&nbsp;after&nbsp;</span><span style="color: #0000ff;">Time</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pid&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">Alarm</span><span style="color: #000000;"><br>end</span><span style="color: #000000;">.</span></div>
<br>&nbsp;&nbsp;&nbsp; <br><span style="font-weight: bold;">5、注册进程</span><br>&nbsp;&nbsp;&nbsp; 为了给进程发送消息，我们需要知道进程的Pid，但是在某些情况下：在一个很大系统里面有很多的全局servers，或者为了安全考虑需要隐藏进程Pid。为了达到可以发送消息给一个不知道Pid的进程的目的，我们提供了注册进程的办法，给进程们注册名字，这些名字必须是atom。<br>&nbsp;&nbsp;&nbsp; 基本的调用形式：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; font-weight: bold;">register(Name,</span><span style="color: #000000;"><span style="font-weight: bold;">&nbsp;Pid)</span><br>将Name与进程Pid联系起来<br><br><span style="font-weight: bold;">unregister(Name)</span><br>取消Name与相应进程的对应关系。<br><br><span style="font-weight: bold;">whereis(Name)</span><br>返回Name所关联的进程的Pid，如果没有进程与之关联，就返回atom</span><span style="color: #000000;">:</span><span style="color: #000000;">undefined<br><br><span style="font-weight: bold;">registered()</span><br>返回当前注册的进程的名字列表</span></div>
<br><span style="font-weight: bold;">6.进程的优先级</span><br>设定进程的优先级可以使用BIFs:<br><span style="font-weight: bold;">process_flag(priority, Pri)</span>
<br><br>Pri可以是normal、low,默认都是normal<br>优先级高的进程将相对低的执行多一点。<br><br><span style="font-weight: bold;">7.进程组（process group)</span><br>&nbsp;&nbsp;&nbsp; 所有的ERLANG进程都有一个Pid与一个他们共有的称为Group Leader相关联，当一个新的进程被创建的时候将被加入同一个进程组。最初的系统进程的Group Leader就是它自身，因此它也是所有被创建进程及子进程的Group Leader。这就意味着Erlang的进程被组织为一棵Tree，其中的根节点就是第一个被创建的进程。下面的BIFs被用于操纵进程组：<br><span style="font-weight: bold;">group_leader()</span><br>返回执行进程的Group Leader的Pid<br><span style="font-weight: bold;">group_leader(Leader, Pid)</span><br>设置进程Pid的Group Leader为进程的Leader
<br><br><span style="font-weight: bold;">8.</span>Erlang的进程模型很容易去构建Client-Server的模型，书中有一节专门讨论了这一点，着重强调了接口的设计以及抽象层次的隔离问题，不翻译了。<br><br>  <img src ="http://www.blogjava.net/killme2008/aggbug/124355.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-06-14 17:12 <a href="http://www.blogjava.net/killme2008/archive/2007/06/14/124355.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang简史（翻译）</title><link>http://www.blogjava.net/killme2008/archive/2007/06/14/124226.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 14 Jun 2007 01:28:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/06/14/124226.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/124226.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/06/14/124226.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/124226.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/124226.html</trackback:ping><description><![CDATA[<img alt="Erlang logo" src="http://www.blogjava.net/killme2008/admin/erlang_small.gif" align="right" border="0">
<h1>Erlang前世今生</h1>
<hr>
<h1>1982 - 1985</h1>
我们使用了 &gt;
20种语言进行了电信行业的编程实验，结论是：这样的语言需要是一门高度的抽象的语言才能达到生产力目标。(给我们留下印象的有：List,Prolog,Parlog
...)
<h1>1985 - 86</h1>
我们使用Lisp,Prolog,Parlog等语言进行了实验，结论是：这样的语言需要原生支持的并发控制和容错处理，并且执行模型必须没有使用回溯。（排除了List和Prolog.)
而且它必须拥有并发粒度比如一个异步的电话进程可以用语言的一个进程表示（排除了Parlog）。最后我们不得不开发一门我们自己的语言，它拥有
Lisp,Prolog和Parlog的特性，但内置了并发和容错处理。
<h1>1987</h1>
第一次使用erlang进行实验。
<h1>1988</h1>
ACS/Dunder（项目)第一阶段：外来用户使用erlang进行PABX(专用自动交换分机)功能的原型构建，
<em>Erlang走出了实验室！</em>
<h1>1989</h1>
<p>&nbsp;ACS/Dunder（项目)第二阶段：重新改造了完整的MD-110系统的1/10，结果:相比于使用PLEX的构建有&gt;&gt;10倍的效率提高！
</p>
<h1>1990</h1>
&nbsp;Erlang正式以ISS'90标准发布，这带来不少的新用户，比如Bellcore。
<h1>1991</h1>
Erlang发布了更快的版本实现给用户，Erlang应用于电信'91（项目？），更多功能比如编译器、图形接口等。
<h1>1992</h1>
&nbsp;更多的新用户，许多高速发展的项目。Erlang可以运行于VxWorks,PC,Macintosh等系统。有三个应用使用了ISS'92标准的Erlang。
<h1>1993</h1>
&nbsp;分布式支持加进了Erlang,这使得erlang可以运行一个自发系统在不同的硬件上。决定向外部发布Erlang的实现，从爱立信分离出独立的部门开始维护和支持Erlang的实现和Erlang工具的开发工作。
<br><img src ="http://www.blogjava.net/killme2008/aggbug/124226.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-06-14 09:28 <a href="http://www.blogjava.net/killme2008/archive/2007/06/14/124226.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang入门（一）</title><link>http://www.blogjava.net/killme2008/archive/2007/06/13/123860.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 13 Jun 2007 06:36:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/06/13/123860.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/123860.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/06/13/123860.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/123860.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/123860.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 读erlang.org上面的Erlang Course四天教程<br><span style="font-weight: bold;">1.</span>数字类型，需要注意两点<br>1）B#Val表示以B进制存储的数字Val，比如<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #800000;">7</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">2</span><span style="color: #008000;">#</span><span style="color: #008000;">101.</span><span style="color: #008000;"><br></span><span style="color: #800000;">5</span><span style="color: #000000;"><br></span></div>
<span style="font-weight: bold;">二</span>进制存储的101就是10进制的5了<br>2）$Char表示字符Char的ascii编码，比如$A表示65<br><br><span style="font-weight: bold;">2.</span>比较难以翻译的概念——atom，可以理解成常量，它可以包含任何字符，以小写字母开头，如果不是以小写字母开头或者是字母之外的符号，需要用单引号包括起来，比如abc,'AB'<br><br><span style="font-weight: bold;">3.</span>另一个概念——Tuple,有人翻译成元组，可以理解成定长数组，是Erlang的基础数据结构之一：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #800000;">8</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;{</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">,</span><span style="color: #800000;">5</span><span style="color: #000000;">}</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>{</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">,</span><span style="color: #800000;">5</span><span style="color: #000000;">}<br></span><span style="color: #800000;">9</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;{a</span><span style="color: #000000;">,</span><span style="color: #000000;">b</span><span style="color: #000000;">,</span><span style="color: #000000;">c</span><span style="color: #000000;">,</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">}</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>{a</span><span style="color: #000000;">,</span><span style="color: #000000;">b</span><span style="color: #000000;">,</span><span style="color: #000000;">c</span><span style="color: #000000;">,</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">}<br></span><span style="color: #800000;">10</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;size({</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">a</span><span style="color: #000000;">,</span><span style="color: #000000;">b</span><span style="color: #000000;">,</span><span style="color: #000000;">c})</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #800000;">6</span><span style="color: #000000;"><br></span></div>
内置函数size求长度，元组可以嵌套元组或者其他结构。下面所讲的列表也一样。<br><br><span style="font-weight: bold;">4.</span>另外一个基础数据结构就是各个语言都有的list（列表），在[]内以,隔开，可以动态改变大小，
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp; [</span><span style="color: #800000;">123</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;xyz]<br>&nbsp;&nbsp;&nbsp;&nbsp;[</span><span style="color: #800000;">123</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;def</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;abc]<br>&nbsp;&nbsp;&nbsp;&nbsp;[{person</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">Joe</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">Armstrong</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">}</span><span style="color: #000000;">,</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{person</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">Robert</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">Virding</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">}</span><span style="color: #000000;">,</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{person</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">Mike</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000; font-weight: bold;">Williams</span><span style="color: #000000; font-weight: bold;">'</span><span style="color: #000000;">}<br>&nbsp;&nbsp;&nbsp;&nbsp;]</span></div>
可以使用内置函数length求列表大小。以""包含的ascii字母代表一个列表，里面的元素就是这些字母的ascii值，比如"abc"表示列表[97,98,99]。<br><br><span style="font-weight: bold;">5.</span>通过这两个数据结构可以组合成各种复杂结构，与Lisp的cons、list演化出各种结构一样的奇妙,Erlang也可以当作是操作列表的语言。<br><br><span style="font-weight: bold;">6.</span>Erlang中变量有两个特点：<br>1）变量必须以大写字母或者下划线开头，可以包含字母、下划线和@<br>2）变量只能绑定一次，也就是所谓的Single Assignment。或者以一般的说法就是只能赋值一次，其实Erlang并没有赋值这样的概念,=号也是用于验证匹配。<br><br><span style="font-weight: bold;">7.</span>模式匹配——Pattern Matching，Erlang的模式匹配非常强大，看了<strong>buaawhl</strong>的《<a href="http://www.javaeye.com/topic/83858">Erlang语法提要</a>》的介绍，模式匹配的功能不仅仅在课程中介绍的数据结构的拆解，在程序的分派也扮演重要角色，或者说Erlang的控制的流转是通过模式匹配来实现的。具体功能参见链接，给出书中拆解列表的例子：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp; [A</span><span style="color: #000000;">,</span><span style="color: #000000;">B</span><span style="color: #000000;">|</span><span style="color: #000000;">C]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">,</span><span style="color: #800000;">5</span><span style="color: #000000;">,</span><span style="color: #800000;">6</span><span style="color: #000000;">,</span><span style="color: #800000;">7</span><span style="color: #000000;">]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Succeeds&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;binds&nbsp;A&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;B&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">,</span><span style="color: #800000;">5</span><span style="color: #000000;">,</span><span style="color: #800000;">6</span><span style="color: #000000;">,</span><span style="color: #800000;">7</span><span style="color: #000000;">]<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;[H</span><span style="color: #000000;">|</span><span style="color: #000000;">T]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Succeeds&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;binds&nbsp;H&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;T&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">]<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;[H</span><span style="color: #000000;">|</span><span style="color: #000000;">T]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[abc]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Succeeds&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;binds&nbsp;H&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;abc</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;T&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[]<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;[H</span><span style="color: #000000;">|</span><span style="color: #000000;">T]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Fails</span></div>
<br>下面会给出更多模式匹配的例子，给出一个模块用来计算列表等<br><br><span style="font-weight: bold;">8.</span>Erlang中函数的定义必须在一个模块内（Module），并且模块和函数的名称都必须是atom，函数的参数可以是任何的Erlang类型或者数据结构，函数要被调用需要从模块中导出，函数调用的形式类似：<br>moduleName:funcName(Arg1,Arg2,...).<br>写我们的第一个Erlang程序，人见人爱的Hello World：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">-</span><span style="color: #000000;">module(helloWorld)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #000000;">-</span><span style="color: #000000;">export([run</span><span style="color: #000000;">/</span><span style="color: #800000;">1</span><span style="color: #000000;">])</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>run(Name)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;io</span><span style="color: #000000;">:</span><span style="color: #0000ff;">format</span><span style="color: #000000;">(</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">Hello&nbsp;World&nbsp;~w~n</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">[Name])</span><span style="color: #000000;">.</span></div>
存为helloWorld.erl，在Erlang Shell中执行：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #800000;">2</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;c(helloWorld)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>{ok</span><span style="color: #000000;">,</span><span style="color: #000000;">helloWorld}<br></span><span style="color: #800000;">3</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;helloWorld</span><span style="color: #000000;">:</span><span style="color: #000000;">run(dennis)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br><span style="font-weight: bold;">Hello&nbsp;World&nbsp;dennis</span><br>ok<br></span></div>
打印出来了，现在解释下程序构造，<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">-</span><span style="color: #000000;">module(helloWorld)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span></div>
这一行声明了模块helloWorld，函数必须定义在模块内，并且模块名称必须与源文件名相同。<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">-</span><span style="color: #000000;">export([run</span><span style="color: #000000;">/</span><span style="color: #800000;">1</span><span style="color: #000000;">])</span><span style="color: #000000;">.</span></div>
而这一行声明导出的函数，run/1指的是有一个参数的run函数，因为Erlang允许定义同名的有不同参数的多个函数，通过指定/1来说明要导出的是哪个函数。<br>接下来就是函数定义了：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">run(Name)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;io</span><span style="color: #000000;">:</span><span style="color: #0000ff;">format</span><span style="color: #000000;">(</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000; font-weight: bold;">Hello&nbsp;World&nbsp;~w~n</span><span style="color: #000000; font-weight: bold;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">[Name])</span><span style="color: #000000;">.</span></div>
大写开头的是变量Name，调用io模块的format方法输出，~w可以理解成占位符，将被实际Name取代，~n就是换行了。注意，函数定义完了要以句号.结束。然后执行c(helloWorld).编译源代码，执行：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">helloWorld</span><span style="color: #000000;">:</span><span style="color: #000000;">run(dennis);</span></div>
<br><span style="font-weight: bold;">9.</span>内置的常用函数：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp; date()<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">time</span><span style="color: #000000;">()<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">length</span><span style="color: #000000;">([</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">,</span><span style="color: #800000;">5</span><span style="color: #000000;">])<br>&nbsp;&nbsp;&nbsp;&nbsp;size({a</span><span style="color: #000000;">,</span><span style="color: #000000;">b</span><span style="color: #000000;">,</span><span style="color: #000000;">c})<br>&nbsp;&nbsp;&nbsp;&nbsp;atom_to_list(an_atom)<br>&nbsp;&nbsp;&nbsp;&nbsp;list_to_tuple([</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">])<br>&nbsp;&nbsp;&nbsp;&nbsp;integer_to_list(</span><span style="color: #800000;">2234</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;tuple_to_list({})<br>&nbsp;&nbsp;&nbsp; hd([1,2,3,4])&nbsp; %输出1，也就是列表的head，类似Lisp的car<br>&nbsp;&nbsp;&nbsp; tl([1,2,3,4])&nbsp; %输出[2,3,4],也就是列表的tail,类似List的cdr<br></span></div>
<br><span style="font-weight: bold;">10.</span>常见Shell命令：<br>1）<span style="font-weight: bold;">h().</span> 用来打印最近的20条历史命令<br>2）<span style="font-weight: bold;">b().</span> 查看所有绑定的变量<br>3) <span style="font-weight: bold;">f().</span> 取消（遗忘）所有绑定的变量。<br>4) <span style="font-weight: bold;">f(Val).</span>&nbsp; 取消指定的绑定变量<br>5) <span style="font-weight: bold;">e(n).</span>&nbsp;&nbsp; 执行第n条历史命令<br>6) <span style="font-weight: bold;">e(-1).</span>&nbsp; 执行上一条shell命令<br><br><span style="font-weight: bold;">11.</span>又一个不知道怎么翻译的概念——Guard。翻译成约束？呵呵。用于限制变量的类型和范围，比如：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp; number(X)&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;是数字<br>&nbsp;&nbsp;&nbsp;&nbsp;integer(X)&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;是整数<br>&nbsp;&nbsp;&nbsp;&nbsp;float(X)&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;是浮点数<br>&nbsp;&nbsp;&nbsp;&nbsp;atom(X)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;是一个atom<br>&nbsp;&nbsp;&nbsp;&nbsp;tuple(X)&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;是一个元组<br>&nbsp;&nbsp;&nbsp;&nbsp;list(X)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;是一个列表<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">length</span><span style="color: #000000;">(X)&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">3</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;是一个长度为3的列表<br>&nbsp;&nbsp;&nbsp;&nbsp;size(X)&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">2</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;是一个长度为2的元组<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;X&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;Y&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;Z&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Y</span><span style="color: #000000;">+</span><span style="color: #000000;">Z<br>&nbsp;&nbsp;&nbsp;&nbsp;X&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;与Y相等<br>&nbsp;&nbsp;&nbsp;&nbsp;X&nbsp;</span><span style="color: #000000;">=:=</span><span style="color: #000000;">&nbsp;Y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;X&nbsp;全等于Y<br>&nbsp;&nbsp;&nbsp;&nbsp;(比如：&nbsp;</span><span style="color: #800000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">1.0</span><span style="color: #000000;">&nbsp;成功<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #800000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">=:=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">1.0</span><span style="color: #000000;">&nbsp;失败)</span></div>
为了方便比较，Erlang规定如下的比较顺序：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">number&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;atom&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;reference&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;port&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;pid&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;tuple&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;list</span></div>
其中pid就是process的id。<br><br><span style="font-weight: bold;">12.</span>忘了介绍apply函数，这个函数对于熟悉javascript的人来说很亲切，javascript实现mixin就得靠它，它的调用方式如下：<br>
<pre>apply(Mod, Func, Args),三个参数分别是模块、函数以及参数列表，比如调用我们的第一个Erlang程序：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">apply(helloWorld</span><span style="color: #000000;">,</span><span style="color: #000000;">run</span><span style="color: #000000;">,</span><span style="color: #000000;">[dennis])</span><span style="color: #000000;">.</span></div>
<span style="font-weight: bold;">13.</span>if和case语句，if语句的结构如下：<br>if<br>   Guard1 -&gt;<br>        Sequence1 ;<br>   Guard2 -&gt;<br>        Sequence2 ;<br>...<br>end<br>而case语句的结构如下：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">case&nbsp;Expr&nbsp;of<br>   Pattern1&nbsp;[when&nbsp;Guard1]&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;Seq1;<br>   Pattern2&nbsp;[when&nbsp;Guard2]&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;Seq2;<br></span><span style="color: #000000;"><img src="http://www.blogjava.net/Images/dot.gif"></span><span style="color: #000000;"><br>   PatternN&nbsp;[when&nbsp;GuardN]&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;SeqN<br>end</span><br> <br></div>
</pre>
if和case语句都有一个问题，就是当没有模式匹配或者Grard都是false的时候会导致error，这个问题case可以增加一个类似java中default的：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">case&nbsp;Fn&nbsp;of<br></span><span style="color: #000000;"><img src="http://www.blogjava.net/Images/dot.gif"></span><span style="color: #000000;"><br>&nbsp;&nbsp; _&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp; true<br>end</span></div>
通过_指代任意的Expr，返回true,而if可以这样：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">if</span><span style="color: #000000;"><br>&nbsp;&nbsp;</span><span style="color: #000000;"><img src="http://www.blogjava.net/Images/dot.gif"></span><span style="color: #000000;"><br>&nbsp;&nbsp;true&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;true<br>end</span></div>
一样的道理。case语句另一个需要注意的问题就是变量范围，每个case分支中定义的变量都将默认导出case语句，也就是在case语句结束后可以被引用，因此一个规则就是每个case分支定义的变量应该一致，不然算是非法的，编译器会给出警告，比如：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">f(X)&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>case&nbsp;g(X)&nbsp;of<br>true&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;A&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;h(X)</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;B&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;A&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">7</span><span style="color: #000000;">;<br>false&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;B&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">6</span><span style="color: #000000;"><br>end</span><span style="color: #000000;">,</span><span style="color: #000000;"><br>h(A)</span><span style="color: #000000;">.</span></div>
<br>如果执行true分支，变量A和变量B都被定义，而如果执行的false分支，只有变量B被定义，可在case语句执行后，h(A)调用了变量A，这是不安全的，因为变量A完全可能没有被定义，编译器将给出警告<br><span style="font-weight: bold;">variable 'A' unsafe in 'case' (line 10)</span><br><br>
<br><br><span style="font-weight: bold;">14.</span>给出一些稍微复杂的模型匹配例子，比如用于计算数字列表的和、平均值、长度、查找某元素是否在列表中，我们把这个模块定义为list:<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">-</span><span style="color: #000000;">module(list)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #000000;">-</span><span style="color: #000000;">export([average</span><span style="color: #000000;">/</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">sum</span><span style="color: #000000;">/</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">len</span><span style="color: #000000;">/</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">double</span><span style="color: #000000;">/</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">member</span><span style="color: #000000;">/</span><span style="color: #800000;">2</span><span style="color: #000000;">])</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>average(X)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">sum(X)</span><span style="color: #000000;">/</span><span style="color: #000000;">len(X)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>sum([H</span><span style="color: #000000;">|</span><span style="color: #000000;">T])&nbsp;when&nbsp;number(H)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">H</span><span style="color: #000000;">+</span><span style="color: #000000;">sum(T);<br>sum([])</span><span style="color: #000000;">-&gt;</span><span style="color: #800000;">0</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>len([_</span><span style="color: #000000;">|</span><span style="color: #000000;">T])</span><span style="color: #000000;">-&gt;</span><span style="color: #800000;">1</span><span style="color: #000000;">+</span><span style="color: #000000;">len(T);<br>len([])</span><span style="color: #000000;">-&gt;</span><span style="color: #800000;">0</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>double([H</span><span style="color: #000000;">|</span><span style="color: #000000;">T])&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;[</span><span style="color: #800000;">2</span><span style="color: #000000;">*</span><span style="color: #000000;">H</span><span style="color: #000000;">|</span><span style="color: #000000;">double(T)];<br>double([])&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;[]</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>member(H</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[H</span><span style="color: #000000;">|</span><span style="color: #000000;">_])&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;true;<br>member(H</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[_</span><span style="color: #000000;">|</span><span style="color: #000000;">T])&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;member(H</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;T);<br>member(_</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;[])&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;false</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><br></span></div>
细细体会，利用递归来实现，比较有趣，这其实与Lisp中利用尾递归来实现迭代是一样的道理，[H|T]的形式类似Lisp中的car、cdr操作。_用于指代任意的变量，当我们只关注此处有变量，但并不关心变量的值的时候使用。用分号;来说明是同一个函数定义，只是不同的定义分支，通过模式匹配来决定调用哪个函数定义分支。<br>另一个例子，计算各种图形的面积，也是课程中给出的例子：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;"><br></span><span style="color: #000000;">-</span><span style="color: #000000;">module(mathStuff)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #000000;">-</span><span style="color: #000000;">export([factorial</span><span style="color: #000000;">/</span><span style="color: #800000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">area</span><span style="color: #000000;">/</span><span style="color: #800000;">1</span><span style="color: #000000;">])</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>factorial(</span><span style="color: #800000;">0</span><span style="color: #000000;">)</span><span style="color: #000000;">-&gt;</span><span style="color: #800000;">1</span><span style="color: #000000;">;<br>factorial(N)&nbsp;when&nbsp;N</span><span style="color: #000000;">&gt;</span><span style="color: #800000;">0</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">N</span><span style="color: #000000;">*</span><span style="color: #000000;">factorial(N</span><span style="color: #000000;">-</span><span style="color: #800000;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #800080;">%计算正方形面积</span><span style="color: #000000;">，参数元组的第一个匹配square&nbsp;&nbsp;&nbsp;&nbsp;<br>area({square</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Side})&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;Side&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;Side;<br></span><span style="color: #800080;">%计算圆的面积</span><span style="color: #000000;">，匹配circle&nbsp;&nbsp;<br>area({circle</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Radius})&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">%</span><span style="color: #000000;">&nbsp;almost&nbsp;</span><span style="color: #000000;">:-</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #800000;">3</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;Radius&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;Radius;<br></span><span style="color: #800080;">%计算三角形的面积</span><span style="color: #000000;">，利用海伦公式，匹配triangle&nbsp;<br>area({triangle</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;A</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;B</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;C})&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;S&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(A&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;B&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;C)</span><span style="color: #000000;">/</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;"><br>math</span><span style="color: #000000;">:</span><span style="color: #0000ff;">sqrt</span><span style="color: #000000;">(S</span><span style="color: #000000;">*</span><span style="color: #000000;">(S</span><span style="color: #000000;">-</span><span style="color: #000000;">A)</span><span style="color: #000000;">*</span><span style="color: #000000;">(S</span><span style="color: #000000;">-</span><span style="color: #000000;">B)</span><span style="color: #000000;">*</span><span style="color: #000000;">(S</span><span style="color: #000000;">-</span><span style="color: #000000;">C));<br></span><span style="color: #800080;">%其他</span><span style="color: #000000;"><br>area(Other)&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;{invalid_object</span><span style="color: #000000;">,</span><span style="color: #000000;">&nbsp;Other}</span><span style="color: #000000;">.</span><span style="color: #000000;"><br><br></span></div>
执行一下看看：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #800000;">1</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;c(mathStuff)</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>{ok</span><span style="color: #000000;">,</span><span style="color: #000000;">mathStuff}<br></span><span style="color: #800000;">2</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;mathStuff</span><span style="color: #000000;">:</span><span style="color: #000000;">area({square</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">})</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #800000;">4</span><span style="color: #000000;"><br></span><span style="color: #800000;">3</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;mathStuff</span><span style="color: #000000;">:</span><span style="color: #000000;">area({circle</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">})</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #800000;">12</span><span style="color: #000000;"><br></span><span style="color: #800000;">4</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;mathStuff</span><span style="color: #000000;">:</span><span style="color: #000000;">area({triangle</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">})</span><span style="color: #000000;">.</span><span style="color: #000000;"><br></span><span style="color: #800000;">2.90474</span><span style="color: #000000;"><br></span><span style="color: #800000;">5</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;mathStuff</span><span style="color: #000000;">:</span><span style="color: #000000;">area({other</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">})</span><span style="color: #000000;">.</span><span style="color: #000000;"><br>{invalid_object</span><span style="color: #000000;">,</span><span style="color: #000000;">{other</span><span style="color: #000000;">,</span><span style="color: #800000;">2</span><span style="color: #000000;">,</span><span style="color: #800000;">3</span><span style="color: #000000;">,</span><span style="color: #800000;">4</span><span style="color: #000000;">}}<br></span></div>
<br>Erlang使用%开始单行注释。<br><img src ="http://www.blogjava.net/killme2008/aggbug/123860.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-06-13 14:36 <a href="http://www.blogjava.net/killme2008/archive/2007/06/13/123860.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>