﻿<?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-庄周梦蝶-随笔分类-动态语言</title><link>http://www.blogjava.net/killme2008/category/19799.html</link><description>天行健，君子以自强不息</description><language>zh-cn</language><lastBuildDate>Sun, 22 Aug 2010 06:00:24 GMT</lastBuildDate><pubDate>Sun, 22 Aug 2010 06:00:24 GMT</pubDate><ttl>60</ttl><item><title>详解Clojure的递归(上）—— 直接递归及优化</title><link>http://www.blogjava.net/killme2008/archive/2010/07/14/326129.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 14 Jul 2010 14:03:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/07/14/326129.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/326129.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/07/14/326129.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/326129.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/326129.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; <a title="详解clojure递归（上）" href="http://www.blogjava.net/killme2008/archive/2010/07/14/326129.html">详解clojure递归（上）</a><br />
&nbsp;&nbsp;&nbsp; <a title="详解clojure递归（下）" href="http://www.blogjava.net/killme2008/archive/2010/08/22/329576.html">详解clojure递归（下）</a><br />
<br />
&nbsp;&nbsp;&nbsp; 递归可以说是LISP的灵魂之一，通过递归可以简洁地描述数学公式、函数调用，Clojure是LISP的方言，同样需要递归来扮演重要作用。递归的价值在于可以让你的思维以what的形式思考，而无需考虑how，你写出来的代码就是数学公式，就是函数的描述，一切显得直观和透明。如果你不习惯递归，那只是因为命令式语言的思维根深蒂固，如x=x+1这样的表达式，从数学的角度来看完全不合法，但是在命令式语言里却是合法的赋值语句。<br />
<br />
&nbsp;&nbsp; 递归可以分为直接递归和间接递归，取决于函数是否直接或者间接地调用自身。如果函数的最后一个调用是递归调用，那么这样的递归调用称为尾递归，针对此类递归调用，编译器可以作所谓的尾递归优化（TCO），因为递归调用是最后一个，因此函数的局部变量等没有必要再保存，本次调用的结果可以完全作为参数传递给下一个递归调用，清空当前的栈并复用，那么就不需要为递归的函数调用保存一长串的栈，因此不会有栈溢出的问题。在Erlang、LISP这样的FP语言里，都支持TCO，无论是直接递归或者间接递归。<br />
<br />
&nbsp;&nbsp; 但是由于JVM自身的限制，Clojure和Scala一样，仅支持直接的尾递归优化，将尾递归调用优化成循环语句。例如一个求阶乘的例子：<br />
&nbsp;&nbsp;&nbsp; <br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">;;第一个版本的阶乘函数<br />
(defn&nbsp;fac&nbsp;[n]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;n)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;n&nbsp;(fac&nbsp;(dec&nbsp;n)))))<br />
</span></div>
<br />
&nbsp;&nbsp; 第一个版本的阶乘并非尾递归，这是因为最后一个表达式的调用是一个乘法运算，而非(fac (dec n))，因此这个版本的阶乘在计算大数的时候会导致栈溢出：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(fac&nbsp;</span><span style="color: #000000;">10000</span><span style="color: #000000;">)<br />
java.lang.StackOverflowError&nbsp;(NO_SOURCE_FILE:</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
</span></div>
<br />
&nbsp;&nbsp; 将第一个版本改进一下，为了让最后一个调用是递归调用，那么我们需要将结果作为参数来传递，而不是倚靠栈来保存，并且为了维持接口一样，我们引入了一个内部函数fac0：<br />
&nbsp;&nbsp;
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp; ;;第二个版本，不是尾递归的&#8220;尾递归&#8221; <br />
&nbsp; (defn&nbsp;fac&nbsp;[n]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(defn&nbsp;fac0&nbsp;[c&nbsp;r]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;c)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<span style="color: red;">fac0</span>&nbsp;(dec&nbsp;c)&nbsp;(</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;c&nbsp;r))))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fac0&nbsp;n&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">))<br />
</span></div>
<br />
&nbsp;&nbsp; 这个是第二个版本的阶乘，通过将结果提取成参数来传递，就将fac0函数的递归调用修改为尾递归的形式，这是个尾递归吗？这在Scala里，在LISP里，这都是尾递归，但是Clojure的TCO优化却是要求使用recur这个特殊形式，而不能直接用函数名作递归调用，因此我们这个第二版本在计算大数的时候仍然将栈溢出：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(fac&nbsp;</span><span style="color: #000000;">10000</span><span style="color: #000000;">)<br />
java.lang.StackOverflowError&nbsp;(NO_SOURCE_FILE:</span><span style="color: #000000;">0</span><span style="color: #000000;">)</span></div>
<br />
&nbsp;&nbsp; 在Clojure里正确地TCO应该是什么样子的呢？其实只要用recur在最后调用那一下替代fac0即可，这就形成我们第三个版本的阶乘：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;&nbsp;;;第三个版本，TCO起作用了<br />
&nbsp;&nbsp;(defn&nbsp;fac&nbsp;[n]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(defn&nbsp;fac0&nbsp;[c&nbsp;r]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;0&nbsp;c)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<span style="color: red;">recur</span> (dec&nbsp;c)&nbsp;(</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;c&nbsp;r))))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fac0&nbsp;n&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">))</span></div>
<br />
&nbsp;&nbsp;&nbsp; 此时你再计算大数就没有问题了，计算(fac 10000)可以正常运行（结果太长，我就不贴出来了）。recur只能跟函数或者loop结合在一起使用，只有函数和loop会形成递归点。我们第三个版本就是利用函数fac0做了尾递归调用的优化。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; loop跟let相似，只不过loop会在顶层形成一个递归点，以便recur重新绑定参数，使用loop改写阶乘函数，这时候就不需要定义内部函数了：
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">;;利用loop改写的第四个版本的阶乘函数<br />
(defn&nbsp;fac&nbsp;[n]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(loop&nbsp;[n&nbsp;n&nbsp;r&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;n&nbsp;0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(recur&nbsp;(dec&nbsp;n)&nbsp;(</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;n&nbsp;r)))))<br />
</span></div>
<br />
&nbsp;&nbsp; loop初始的时候将n绑定为传入的参数n（由于作用域不同，同名没有问题），将r绑定为1，最后recur就可以将新的参数值绑定到loop的参数列表并递归调用。<br />
<br />
&nbsp;&nbsp; Clojure的TCO是怎么做到的，具体可以看看我前两天写的<a href="http://www.blogjava.net/killme2008/archive/2010/07/11/325766.html">这篇博客</a>，本质上是在编译的时候将最后的递归调用转化成一条goto语句跳转到开始的Label，也就是转变成了循环调用。<br />
<br />
&nbsp;&nbsp; 这个阶乘函数仍然有优化的空间，可以看到，每次计算其实都有部分是重复计算的，如计算(fac 5)也就是1*2*3*4*5，计算(fac 6)的1*2*3*4*5*6，如果能将前面的计算结果缓存下来，那么计算(fac 6)的时候将更快一些，这可以通过memoize函数来包装阶乘函数：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; 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: #0000ff;">def</span><span style="color: #000000;">&nbsp;fac&nbsp;(<span style="color: red;">memoize</span>&nbsp;fac))</span></div>
<br />
第一次计算(fac 10000)花费的时间长一些，因为还没有缓存：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(time&nbsp;(fac&nbsp;</span><span style="color: #000000;">10000</span><span style="color: #000000;">))&nbsp;<br />
</span><span style="color: #800000;">"</span><span style="color: #800000;">Elapsed&nbsp;time:&nbsp;170.489622&nbsp;msecs</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
<br />
</span></div>
<br />
第二次计算快了非常多（其实没有计算，只是返回缓存结果）：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(time&nbsp;(fac&nbsp;</span><span style="color: #000000;">10000</span><span style="color: #000000;">))<br />
</span><span style="color: #800000;">"</span><span style="color: #800000;">Elapsed&nbsp;time:&nbsp;0.058737&nbsp;msecs</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp;
可以看到，如果没有预先缓存，利用memoize包装的阶乘函数也是快不了。memoize的问题在于，计算(fac n)路径上的没有用到的值都不会缓存，它只缓存最终的结果，因此如果计算n前面的其他没有计算过的数字，仍然需要重新计算。那么怎么保存路径上的值呢？这可以将求阶乘转化成另一个等价问题来解决。<br />
&nbsp;&nbsp;&nbsp; 我们可以将所有的阶乘结果组织成一个无穷集合，求阶乘变成从<strong>这个集合里取第n个元素</strong>，这是利用Clojure里集合是lazy的特性，集合里的元素如果没有使用到，那么就不会预先计算，而是等待要用到的时候才计算出来，定义一个阶乘结果的无穷集合，可以利用map将fac作用在整数集合上,map、reduce这样的高阶函数返回的是LazySeq：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;fac</span><span style="color: #000000;">-</span><span style="color: #000000;">seq&nbsp;(map&nbsp;fac&nbsp;(iterate&nbsp;inc&nbsp;0)))</span></div>
<br />
&nbsp;&nbsp; (iterate inc 0)定义了正整数集合包括0，0的阶乘没有意义。这个集合的第0项其实是多余的。<br />
&nbsp;&nbsp; 查看fac-seq的类型，这是一个LazySeq:<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;fac</span><span style="color: #000000;">-</span><span style="color: #000000;">seq)<br />
clojure.lang.LazySeq<br />
</span></div>
<br />
&nbsp; 求n的阶乘，等价于从这个集合里取第n个元素：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(nth&nbsp;fac</span><span style="color: #000000;">-</span><span style="color: #000000;">seq&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;">)<br />
</span><span style="color: #000000;">3628800</span><span style="color: #000000;"><br />
</span></div>
<br />
&nbsp; 这个集合会比较耗内存，因为会缓存所有计算路径上的独立的值，哪怕他们暂时不会被用到。但是这种采用LazySeq的方式来定义阶乘函数的方式有个优点，那就是在定义fac-seq使用的f<span style="color: red;">ac函数无需一定是符合TCO的函数</span>，我们的第一个版本的阶乘函数稍微修改下也可以使用，并且不会栈溢出：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(defn&nbsp;fac&nbsp;[n]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;n&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;n&nbsp;(fac&nbsp;(dec&nbsp;n)))))<br />
<br />
(</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;fac&nbsp;(memoize&nbsp;fac))<br />
(</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;fac</span><span style="color: #000000;">-</span><span style="color: #000000;">seq&nbsp;(map&nbsp;fac&nbsp;(iterate&nbsp;inc&nbsp;0)))<br />
(nth&nbsp;fac</span><span style="color: #000000;">-</span><span style="color: #000000;">seq&nbsp;</span><span style="color: #000000;">10000</span><span style="color: #000000;">)<br />
<br />
</span></div>
<br />
&nbsp; 因为集合从0开始，因此只是修改了fac的if条件为n&lt;=1的时候返回1。至于为什么这样就不会栈溢出，有兴趣的朋友可以自己思考下。<br />
<br />
&nbsp;&nbsp;&nbsp; 从这个例子也可以看出，一些无法TCO的递归调用可以转化为LazySeq来处理，这算是弥补JVM缺陷的一个办法。<br />
&nbsp;&nbsp;&nbsp; <br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/326129.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-07-14 22:03 <a href="http://www.blogjava.net/killme2008/archive/2010/07/14/326129.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure的并发（一） Ref和STM</title><link>http://www.blogjava.net/killme2008/archive/2010/07/14/326027.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 13 Jul 2010 18:34:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/07/14/326027.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/326027.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/07/14/326027.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/326027.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/326027.html</trackback:ping><description><![CDATA[<br />
<a id="Editor_Results_rprSelectionList_ctl09_LinkTitle" class="titlelink" href="../archive/2010/07/14/326027.html">Clojure
的并发（一） Ref和STM</a>
<br />
<a id="Editor_Results_rprSelectionList_ctl06_Hyperlink1" class="titlelink" href="../archive/2010/07/17/326362.html">Clojure
的并发（二）Write Skew分析</a><br />
<a id="Editor_Results_rprSelectionList_ctl05_LinkTitle" class="titlelink" href="../archive/2010/07/17/326389.html">Clojure
的并发（三）Atom、缓存和性能</a>
<br />
<a id="Editor_Results_rprSelectionList_ctl04_Hyperlink1" class="titlelink" href="../archive/2010/07/19/326540.html">Clojure
的并发（四）Agent深入分析和Actor</a>
<br />
<a id="Editor_Results_rprSelectionList_ctl01_LinkTitle" class="titlelink" href="../archive/2010/07/23/326976.html">Clojure
的并发（五）binding和let</a>
<br />
<a title="Clojure的并发（六）Agent可以改进的地方" href="http://www.blogjava.net/killme2008/archive/2010/07/30/327606.html">Clojure的并发（六）Agent可以改进的地方</a><br />
<a title="Clojure的并发（七）pmap、pvalues和pcalls" href="http://www.blogjava.net/killme2008/archive/2010/08/04/327985.html">Clojure的并发（七）pmap、pvalues和pcalls</a><br />
<a title="Clojure的并发（八）future、promise和线程" href="http://www.blogjava.net/killme2008/archive/2010/08/08/328230.html">Clojure的并发（八）future、promise和线程</a><br />
<br />
&nbsp;&nbsp;&nbsp; Clojure处理并发的思路与众不同，采用的是所谓<a href="http://en.wikipedia.org/wiki/Software_transactional_memory">STM</a>的模型——软事务内存。你可以将STM想象成数据库，只不过是内存型的，它只支持事务的ACI，也就是原子性、一致性、隔离性，但是不包括持久性，因为状态的保存都在内存里。<br />
<br />
&nbsp;&nbsp;&nbsp; Clojure的并发API分为四种模型：<br />
1、管理协作式、同步修改可变状态的Ref<br />
2、管理非协作式、同步修改可变状态的Atom<br />
3、管理异步修改可变状态的Agent<br />
4、管理Thread local变量的Var。<br />
<br />
&nbsp;&nbsp;&nbsp; 下面将对这四部分作更详细的介绍。<br />
<br />
<strong>一、Ref和STM</strong><br />
<br />
<strong>&nbsp;1、ref:</strong><br />
<br />
通过ref函数创建一个可变的引用(reference)，指向一个不可变的对象：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(ref&nbsp;x)</span></div>
<br />
例子：创建一个歌曲集合：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(def&nbsp;song&nbsp;(ref&nbsp;#{}))</span></div>
<br />
<strong>2、deref和@:</strong><br />
&nbsp;取引用的内容，解引用使用deref函数<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(deref song)</span></div>
<br />
也可以用reader宏@：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">@song</span></div>
<strong><br />
3、ref-set和dosync:</strong><br />
<br />
改变引用指向的内容，使用ref-set函数<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(ref</span><span style="color: #000000;">-</span><span style="color: #000000;">set&nbsp;ref&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">-</span><span style="color: #000000;">value)</span></div>
<br />
如，我们设置新的歌曲集合，加入一首歌：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(ref</span><span style="color: #000000;">-</span><span style="color: #000000;">set&nbsp;song&nbsp;#{</span><span style="color: #000000;">"</span><span style="color: #000000;">Dangerous</span><span style="color: #000000;">"</span><span style="color: #000000;">})</span></div>
但是这样会报错：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">java.lang.IllegalStateException:&nbsp;No&nbsp;transaction&nbsp;running&nbsp;(NO_SOURCE_FILE:</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
</span></div>
<br />
这是因为引用是可变的，对状态的更新需要进行保护，传统语言的话可能采用锁，Clojure是采用事务，将更新包装到事务里，这是通过dosync实现的：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(dosync&nbsp;(ref</span><span style="color: #000000;">-</span><span style="color: #000000;">set&nbsp;song&nbsp;#{</span><span style="color: #000000;">"</span><span style="color: #000000;">Dangerous</span><span style="color: #000000;">"</span><span style="color: #000000;">}))</span></div>
<br />
dosync的参数接受多个表达式，这些表达式将被包装在一个事务里，事务支持ACI：<br />
（1）Atomic，如果你在事务里更新多个Ref，那么这些更新对事务外部来说是一个独立的操作。<br />
（2）Consistent，Ref的更新可以设置 validator，如果某个验证失败，整个事务将回滚。<br />
（3）Isolated，运行中的事务无法看到其他事务部分完成的结果。<br />
<br />
dosync更新多个Ref，假设我们还有个演唱者Ref，同时更新歌曲集合和演唱者集合:<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(def&nbsp;singer&nbsp;(ref&nbsp;#{}))<br />
(dosync&nbsp;(ref</span><span style="color: #000000;">-</span><span style="color: #000000;">set&nbsp;song&nbsp;#{</span><span style="color: #000000;">"</span><span style="color: #000000;">Dangerous</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;(ref</span><span style="color: #000000;">-</span><span style="color: #000000;">set&nbsp;singer&nbsp;#{</span><span style="color: #000000;">"</span><span style="color: #000000;">MJ</span><span style="color: #000000;">"</span><span style="color: #000000;">})&nbsp;)<br />
<br />
@song&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;&nbsp;#{</span><span style="color: #000000;">"</span><span style="color: #000000;">Dangerous</span><span style="color: #000000;">"</span><span style="color: #000000;">}<br />
@singer&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;&nbsp;#{</span><span style="color: #000000;">"</span><span style="color: #000000;">MJ</span><span style="color: #000000;">"</span><span style="color: #000000;">}<br />
</span></div>
<br />
<strong>4、alter:</strong><br />
完全更新整个引用的值还是比较少见，更常见的更新是根据当前状态更新，例如我们向歌曲集合添加一个歌曲，步骤大概是先查询集合内容，然后往集合里添加歌曲，然后更新整个集合：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(dosync&nbsp;(ref</span><span style="color: #000000;">-</span><span style="color: #000000;">set&nbsp;song&nbsp;(conj&nbsp;@song&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">heal&nbsp;the&nbsp;world</span><span style="color: #000000;">"</span><span style="color: #000000;">)))</span></div>
<br />
查询并更新的操作可以合成一步，这是通过alter函数：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(alter&nbsp;ref&nbsp;update</span><span style="color: #000000;">-</span><span style="color: #000000;">fn&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;args<img src="http://www.blogjava.net/Images/dot.gif" alt="" />)<br />
</span></div>
<br />
alter接收一个更新的函数，函数将在更新的时候调用，传入当前状态值并返回新的状态值，因此上面的例子可以改写为：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;(dosync&nbsp;(alter&nbsp;song&nbsp;conj&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">heal&nbsp;the&nbsp;world</span><span style="color: #000000;">"</span><span style="color: #000000;">))</span></div>
<br />
这里使用conj而非cons是因为conj接收的第一个参数是集合，也就是当前状态值，而cons要求第一个参数是将要加入的元素。<br />
<br />
<strong>5、commute：</strong><br />
&nbsp; commute函数是alter的变形，commute顾名思义就是要求update-function是可交换的，它的顺序是可以任意排序。commute的允许的并发程度比alter更高一些，因此性能会更好。但是由于commute要求update-function是可交换的，并且会自动重排序，因此如果你的更新要求顺序性，那么commute是不能接受的,commute仅可用在对顺序性没有要求或者要求很低的场景：例如更新聊天窗口的聊天信息，由于网络延迟的因素和个人介入的因素，聊天信息可以认为是天然排序，因此使用commute还可以接受，更新乱序的可能性很低。<br />
&nbsp; 另一个例子就不能使用commute了，如实现一个计数器：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(def&nbsp;counter&nbsp;(ref&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">))<br />
</span></div>
<br />
&nbsp; 实现一个next-counter函数获取计数器的下一个值，我们先使用commute实现：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(defn&nbsp;next</span><span style="color: #000000;">-</span><span style="color: #000000;">counter&nbsp;[]&nbsp;(dosync&nbsp;(commute&nbsp;counter&nbsp;inc)))</span></div>
<br />
&nbsp;&nbsp;
这个函数很简单，每次调用inc递增counter的值，接下来写个测试用例：启动50个线程并发去获取next counter:<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(dotimes&nbsp;[_&nbsp;</span><span style="color: #000000;">50</span><span style="color: #000000;">]&nbsp;(.start&nbsp;(Thread.&nbsp;#(println&nbsp;(next</span><span style="color: #000000;">-</span><span style="color: #000000;">counter)))))</span></div>
&nbsp;&nbsp; <br />
&nbsp;&nbsp; 这段代码稍微解释下，dotimes是重复执行50次，每次启动new并启动一个Thread,这个Thread里干了两件事情：调用next-counter，打印调用结果,第一个版本的next-counter执行下，这是其中一次输出的截取：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
<br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">28</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">21</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">23</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">25</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">28</span><span style="color: #000000;"><br />
</span></div>
<br />
可以看到有很多的重复数值，这是由于重排序导致事务结束后的值不同，但是你查看counter，确实是50:<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">@counter&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">50</span></div>
<br />
证明更新是没有问题的，问题出在commute的返回值上。<br />
<br />
如果将next-counter修改为alter实现：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(defn&nbsp;next</span><span style="color: #000000;">-</span><span style="color: #000000;">counter&nbsp;[]&nbsp;(dosync&nbsp;(alter&nbsp;counter&nbsp;inc)))</span></div>
<br />
此时再执行测试用例，可以发现打印结果完全正确了：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&#8230;&#8230;<br />
</span><span style="color: #000000;">39</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">41</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">42</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">45</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">27</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">46</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">47</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">44</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">48</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">43</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">49</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">40</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">50</span><span style="color: #000000;"><br />
</span></div>
<br />
查看counter，也是正确更新到50了：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">@counter&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">50</span></div>
<br />
最佳实践：<strong>通常情况下，你应该优先使用alter</strong>，除非在遇到明显的性能瓶颈并且对顺序不是那么关心的时候，可以考虑用commute替换。<br />
<br />
<strong>6、validator：</strong><br />
&nbsp;&nbsp; 类似数据库，你也可以为Ref添加&#8220;约束&#8221;，在数据更新的时候需要通过validator函数的验证，如果验证不通过，整个事务将回滚。添加validator是通过ref函数传入metadata的map实现的，例如我们要求歌曲集合添加的歌曲名称不能为空：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(def validate</span><span style="color: #000000;">-</span><span style="color: #000000;">song<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(partial&nbsp;every? #(not (nil? </span><span style="color: #000000;">%</span><span style="color: #000000;">))))<br />
<br />
(def&nbsp;song&nbsp;(ref&nbsp;#{}&nbsp;:validator&nbsp;validate</span><span style="color: #000000;">-</span><span style="color: #000000;">song))</span></div>
<br />
validate-song是一个验证函数，partial返回某个函数的半函数（固定了部分参数，部分参数没固定），你可以将partial理解成currying，虽然还是不同的。validate-song调用every?来验证集合内的所有元素都不是nil，其中#(not (nil? %))是一个匿名函数，%指向匿名函数的第一个参数，也就是集合的每个元素。ref指定了validator为validate-song，那么在每次更新song集合的时候都会将新的状态传入validator函数里验证一下，如果返回false，整个事务将回滚：<br />
<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(dosync&nbsp;(alter&nbsp;song&nbsp;conj&nbsp;nil))<br />
java.lang.IllegalStateException:&nbsp;Invalid&nbsp;reference&nbsp;state&nbsp;(NO_SOURCE_FILE:</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
</span></div>
<br />
更新失败，非法的reference状态，查看song果然还是空的：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">@song&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;#{}</span></div>
<br />
更新正常的值就没有问题：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">&nbsp;(dosync&nbsp;(alter&nbsp;song&nbsp;conj&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">dangerous</span><span style="color: #000000;">"</span><span style="color: #000000;">))&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;#{</span><span style="color: #000000;">"</span><span style="color: #000000;">dangerous</span><span style="color: #000000;">"</span><span style="color: #000000;">}</span></div>
<br />
&nbsp;&nbsp;&nbsp; <br />
<strong>7、ensure:</strong><br />
<br />
&nbsp; ensure函数是为了保护Ref不会被其他事务所修改，它的主要目的是为了防止所谓的&#8220;<strong>写偏序</strong>&#8221;(<strong>write skew</strong>)问题。写偏序问题的产生跟STM的实现有关，clojure的STM实现是基于<a href="http://en.wikipedia.org/wiki/Multiversion_concurrency_control">MVCC(Multiversion Concurrency Control)</a>——多版本并发控制，对一个Ref保存多个版本的状态值，在更新的时候取得当前状态值的一个隔离的snapshot，更新是基于snapshot进行的。那么我们来看下写偏序是怎么产生，以一个比喻来描述：<br />
&nbsp; 想象有一个系统用于管理美国最神秘的军事禁区——51区的安全巡逻，你有3个营的士兵，每个营45个士兵，并且你<strong>需要保证总体巡逻的士兵人数不能少于100个人</strong>。假设有一天，有两个指挥官都登录了这个管理系统，他们都想从某个军营里抽走20个士兵，假设指挥官A想从1号军营抽走，指挥官B想要从2号军营抽走士兵，他们同时执行下列操作：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">Admin&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">:&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;((G1&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">20</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;G2&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;G3)&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">100</span><span style="color: #000000;">&nbsp;then&nbsp;dispatchPatrol<br />
<br />
Admin&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">:&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(G1&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;(G2&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">20</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;G3)&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">100</span><span style="color: #000000;">&nbsp;then&nbsp;dispatchPatrol</span></div>
<br />
我们刚才提到，Clojure的更新是基于隔离的snapshot，一个事务的更改无法看到另一个事务更改了部分的结果，因此这两个操作都因为满足(45-20)+45+45=115的约束而得到执行，导致实际抽调走了40个士兵，只剩下95个士兵，低于设定的安全标准100人，这就是写偏序现象。<br />
&nbsp; 写偏序的解决就很简单，在执行抽调前加入ensure即可保护ref不被其他事务所修改。ensure比(ref-set ref @ref)允许的并发程度更高一些。<br />
<br />
<br />
Ref和STM的介绍暂时到这里，原理和源码的解析要留待下一篇文章了。<br />
<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/326027.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-07-14 02:34 <a href="http://www.blogjava.net/killme2008/archive/2010/07/14/326027.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure的dosync是正则序？</title><link>http://www.blogjava.net/killme2008/archive/2010/07/13/325939.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 13 Jul 2010 04:02:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/07/13/325939.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/325939.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/07/13/325939.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/325939.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/325939.html</trackback:ping><description><![CDATA[<br />
&nbsp;&nbsp;&nbsp; 解释器求值的顺序可以分为应用序和正则序，应用序是先求值参数，再执行表达式；正则序则是先将表达式按照实际参数展开，然后再执行。具体可以看看过去写的<a href="http://www.blogjava.net/killme2008/archive/2007/05/08/115949.html">这篇文章</a>。<br />
<br />
&nbsp;&nbsp; Clojure的求值可以肯定是应用序的，如执行<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">(defn&nbsp;mytest&nbsp;[a&nbsp;b]&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: rgb(0, 0, 255);">if</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);">&nbsp;a&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b))<br />
(mytest&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
</span></div>
<br />
尽管在(mytest 0 1/0)中a绑定为0，如果求值器是完全展开再求值，那应该正常执行并返回a，也就是1；但是因为clojure是应用序，因此参数b的1/0会先计算，这显然会报错。<br />
<br />
&nbsp;&nbsp; clojure的dosync用于将一些表达式包装成事务，Ref的更新操作没有包装在事务里，会抛出异常<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">;;定义mutable的Ref<br />
&nbsp;(def&nbsp;song&nbsp;(ref&nbsp;#{}))<br />
<br />
;;添加一首歌<br />
(alter&nbsp;song&nbsp;conj&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">dangerous</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">)</span></div>
<br />
&nbsp;&nbsp; alter用于向Ref查询并添加元素，用conj将"dangerous"这首歌加入集合，但是alter要求执行在一个事务里，因此上面的代码会报错<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">java.lang.IllegalStateException:&nbsp;No&nbsp;transaction&nbsp;running&nbsp;(NO_SOURCE_FILE:</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">)</span></div>
<br />
&nbsp;&nbsp; 如果你用dosync包装就没有问题<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">user</span><span style="color: rgb(0, 0, 0);">=&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;(dosync&nbsp;(alter&nbsp;song&nbsp;conj&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">dangerous</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">))<br />
#{</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">dangerous</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">}</span></div>
<br />
&nbsp;&nbsp; 返回更新后的结果集合。这个跟我们要谈的正则序和应用序有什么关系呢？可能你看出来了，如果说clojure是应用序，那么在表达式<span style="color: rgb(0, 0, 0);"> (dosync&nbsp;(alter&nbsp;song&nbsp;conj&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">dangerous</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">))中，alter也应该先执行，应当照样报</span>"<span style="color: rgb(0, 0, 0);"> No&nbsp;transaction&nbsp;running"的错误才对，为何却没有呢？难道dosync是按照正则序执行？<br />
<br />
&nbsp;&nbsp; 查看dosync的文档<br />
</span>
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">user</span><span style="color: rgb(0, 0, 0);">=&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;(doc&nbsp;dosync)<br />
</span><span style="color: rgb(0, 0, 0);">-------------------------</span><span style="color: rgb(0, 0, 0);"><br />
clojure.core</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">dosync<br />
([</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">&nbsp;exprs])<br />
Macro<br />
&nbsp;&nbsp;Runs&nbsp;the&nbsp;exprs&nbsp;(in&nbsp;an&nbsp;implicit&nbsp;</span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);">)&nbsp;in&nbsp;a&nbsp;transaction&nbsp;that&nbsp;encompasses<br />
&nbsp;&nbsp;exprs&nbsp;and&nbsp;any&nbsp;nested&nbsp;calls.&nbsp;&nbsp;Starts&nbsp;a&nbsp;transaction&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;none&nbsp;is&nbsp;already<br />
&nbsp;&nbsp;running&nbsp;on&nbsp;</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">&nbsp;thread.&nbsp;Any&nbsp;uncaught&nbsp;exception&nbsp;will&nbsp;abort&nbsp;the<br />
&nbsp;&nbsp;transaction&nbsp;and&nbsp;flow&nbsp;out&nbsp;of&nbsp;dosync.&nbsp;The&nbsp;exprs&nbsp;may&nbsp;be&nbsp;run&nbsp;more&nbsp;than<br />
&nbsp;&nbsp;once,&nbsp;but&nbsp;any&nbsp;effects&nbsp;on&nbsp;Refs&nbsp;will&nbsp;be&nbsp;atomic.<br />
</span></div>
<br />
&nbsp;&nbsp; 这是一个宏，他的作用是将表达式包装在一个事务里，如果当前线程没有事务，那么就启动一个。<br />
查看源码：<br />
<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">(defmacro&nbsp;dosync<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Runs&nbsp;the&nbsp;exprs&nbsp;(in&nbsp;an&nbsp;implicit&nbsp;do)&nbsp;in&nbsp;a&nbsp;transaction&nbsp;that&nbsp;encompasses</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;exprs&nbsp;and&nbsp;any&nbsp;nested&nbsp;calls.&nbsp;&nbsp;Starts&nbsp;a&nbsp;transaction&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;none&nbsp;is&nbsp;already<br />
&nbsp;&nbsp;running&nbsp;on&nbsp;</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">&nbsp;thread.&nbsp;Any&nbsp;uncaught&nbsp;exception&nbsp;will&nbsp;abort&nbsp;the<br />
&nbsp;&nbsp;transaction&nbsp;and&nbsp;flow&nbsp;out&nbsp;of&nbsp;dosync.&nbsp;The&nbsp;exprs&nbsp;may&nbsp;be&nbsp;run&nbsp;more&nbsp;than<br />
&nbsp;&nbsp;once,&nbsp;but&nbsp;any&nbsp;effects&nbsp;on&nbsp;Refs&nbsp;will&nbsp;be&nbsp;atomic.</span><span style="color: rgb(0, 0, 0);">"<br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;[</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">&nbsp;exprs]<br />
&nbsp;&nbsp;`(sync&nbsp;nil&nbsp;</span><span style="color: rgb(0, 0, 0);">~</span><span style="color: rgb(0, 0, 0);">@exprs))</span></div>
<br />
&nbsp;&nbsp; 本质上dosync是调用了sync这个宏，sync干了些什么？<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">(defmacro&nbsp;sync<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">transaction-flags&nbsp;=&gt;&nbsp;TBD,&nbsp;pass&nbsp;nil&nbsp;for&nbsp;now</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;Runs&nbsp;the&nbsp;exprs&nbsp;(in&nbsp;an&nbsp;implicit&nbsp;</span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);">)&nbsp;in&nbsp;a&nbsp;transaction&nbsp;that&nbsp;encompasses<br />
&nbsp;&nbsp;exprs&nbsp;and&nbsp;any&nbsp;nested&nbsp;calls.&nbsp;&nbsp;Starts&nbsp;a&nbsp;transaction&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;none&nbsp;is&nbsp;already<br />
&nbsp;&nbsp;running&nbsp;on&nbsp;</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">&nbsp;thread.&nbsp;Any&nbsp;uncaught&nbsp;exception&nbsp;will&nbsp;abort&nbsp;the<br />
&nbsp;&nbsp;transaction&nbsp;and&nbsp;flow&nbsp;out&nbsp;of&nbsp;sync.&nbsp;The&nbsp;exprs&nbsp;may&nbsp;be&nbsp;run&nbsp;more&nbsp;than<br />
&nbsp;&nbsp;once,&nbsp;but&nbsp;any&nbsp;effects&nbsp;on&nbsp;Refs&nbsp;will&nbsp;be&nbsp;atomic.</span><span style="color: rgb(0, 0, 0);">"<br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;[flags</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">ignored</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">now&nbsp;</span><span style="color: rgb(0, 0, 0);">&amp;</span><span style="color: rgb(0, 0, 0);">&nbsp;body]<br />
&nbsp;&nbsp;`(.&nbsp;clojure.lang.LockingTransaction<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(runInTransaction&nbsp;(fn&nbsp;[]&nbsp;</span><span style="color: rgb(0, 0, 0);">~</span><span style="color: rgb(0, 0, 0);">@body))))</span></div>
<br />
&nbsp;&nbsp; 找到了，原来是调用了<span style="color: rgb(0, 0, 0);">clojure.lang.LockingTransaction.</span><span style="color: rgb(0, 0, 0);">runInTransaction这个静态方法，并且将exps包装成一个匿名函数<br />
<br />
</span>
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">fn&nbsp;[]&nbsp;</span><span style="color: rgb(0, 0, 0);">~</span><span style="color: rgb(0, 0, 0);">@body</span></div>
<br />
&nbsp; <span style="color: rgb(0, 0, 0);">&nbsp;&nbsp; </span> 因此，dosync并非正则序,<span style="color: rgb(0, 0, 0);">dosync是个宏，</span><span style="color: rgb(0, 0, 0);">(dosync&nbsp;(alter&nbsp;song&nbsp;conj&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">dangerous</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 />
</span>
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">(sync&nbsp;nil&nbsp;(fun&nbsp;[]&nbsp;(alter&nbsp;song&nbsp;conj&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">dangerous</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">)))</span></div>
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; 这就解答了为什么<span style="color: rgb(0, 0, 0);">(dosync&nbsp;(alter&nbsp;song&nbsp;conj&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">dangerous</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">))</span><span style="color: rgb(0, 0, 0);">可以正常运行的疑问。宏的使用，首先是展开，然后才是按照应用序的顺序求值。</span><br />
<span style="color: rgb(0, 0, 0);"><br />
<br />
</span>&nbsp;&nbsp; <br />
<br />
<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/325939.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-07-13 12:02 <a href="http://www.blogjava.net/killme2008/archive/2010/07/13/325939.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure Hacking Guide</title><link>http://www.blogjava.net/killme2008/archive/2010/07/11/325775.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 11 Jul 2010 04:07:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/07/11/325775.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/325775.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/07/11/325775.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/325775.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/325775.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 这题目起的哗众取宠，其实只是想介绍下怎么查看Clojure动态生成的字节码，这对分析Clojure的内部实现很重要。<br />
<br />
&nbsp;&nbsp;&nbsp; 第一步，下载最新的<a href="http://github.com/downloads/clojure/clojure/clojure-1.1.0.zip">Clojure 1.1.0源码</a>并解压，并导入到你喜欢的IDE。<br />
<br />
&nbsp;&nbsp;&nbsp; 其次，下载<a href="http://forge.ow2.org/project/download.php?group_id=23&amp;file_id=7262">asm 3.0的源码</a>并解压。<br />
<br />
&nbsp;&nbsp;&nbsp; 第三，删除Clojure 1.1.0源码中的clojure.asm包。clojure并不是引用asm的jar包，而是将asm的源码合并到clojure中，并且删除一些只会在调试阶段用到的package和class，保留使用asm的最小源码集合，这可能是处于防止asm不同版本的jar包冲突以及缩小clojure大小的考虑。<br />
<br />
&nbsp;&nbsp;&nbsp; 第四，将asm 3.0源码拷入clojure的源码中，并将包org.objectweb.asm包括子包整体重名名为clojure.asm。<br />
<br />
&nbsp;&nbsp;&nbsp; 第五步，修改Clojure源码，加入TraceClassVisitor的适配器，用于跟踪字节码生成，这需要修改clojure.lang.Compiler类中的两个compile方法，找到类似<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">ClassWriter&nbsp;cw&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;ClassWriter(ClassWriter.COMPUTE_MAXS);<br />
</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;ClassWriter&nbsp;cw&nbsp;=&nbsp;new&nbsp;ClassWriter(0);</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">ClassVisitor&nbsp;cv&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;cw;</span></div>
<br />
这样的代码，将cv修改为TraceClassVisitor：<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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;ClassVisitor&nbsp;cv&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;TraceClassVisitor(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;CheckClassAdapter(cw),&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;PrintWriter(System.out));</span></div>
<br />
&nbsp;&nbsp;&nbsp; TraceClassVisitor的第二个参数指定将跟踪到的字节码输出到哪里，这里简单地输出到标准输出方便查看。<br />
<br />
&nbsp;&nbsp;&nbsp; 第六步，接下来可以尝试下我们修改过的clojure怎么动态生成字节码,启动REPL，<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">java&nbsp;clojure.main</span></div>
<br />
启动阶段就会输出一些字节码信息，主要预先加载的一些标准库函数，如clojure.core中的函数等，REPL启动完毕，随便输入一个表达式都将看到生成的字节码<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">user</span><span style="color: rgb(0, 0, 0);">=&gt;</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);">&nbsp;</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">)<br />
</span></div>
<br />
输出类似<br />
<br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; 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);">compile&nbsp;</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;class&nbsp;version&nbsp;49.0&nbsp;(49)<br />
</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;access&nbsp;flags&nbsp;33</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;user$eval__4346&nbsp;</span><span style="color: rgb(0, 0, 255);">extends</span><span style="color: rgb(0, 0, 0);">&nbsp;clojure</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">AFunction&nbsp;&nbsp;{<br />
<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;compiled&nbsp;from:&nbsp;NO_SOURCE_FILE<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;debug&nbsp;info:&nbsp;SMAP</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">eval__4346.java<br />
Clojure<br />
</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">S&nbsp;Clojure<br />
</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">F<br />
</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);">1</span><span style="color: rgb(0, 0, 0);">&nbsp;NO_SOURCE_FILE<br />
NO_SOURCE_PATH<br />
</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">L<br />
</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">#</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">:</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">E<br />
<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;access&nbsp;flags&nbsp;25</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">final</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);">&nbsp;Lclojure</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Var;&nbsp;const__0<br />
<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;access&nbsp;flags&nbsp;25</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">final</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);">&nbsp;Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Object;&nbsp;const__1<br />
<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;access&nbsp;flags&nbsp;25</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">final</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);">&nbsp;Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Object;&nbsp;const__2<br />
<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;access&nbsp;flags&nbsp;9</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);"><span style="background-color: yellow;"><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">clinit</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">()V</span></span></span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;L0<br />
&nbsp;&nbsp;&nbsp;&nbsp;LINENUMBER&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">&nbsp;L0<br />
&nbsp;&nbsp;&nbsp;&nbsp;LDC&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">clojure.core</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;LDC&nbsp;</span><span style="color: rgb(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 />
&nbsp;&nbsp;&nbsp;&nbsp;INVOKESTATIC&nbsp;clojure</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">RT.var&nbsp;(Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">String;Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">String;)Lclojure</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Var;<br />
&nbsp;&nbsp;&nbsp;&nbsp;CHECKCAST&nbsp;clojure</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Var<br />
&nbsp;&nbsp;&nbsp;&nbsp;PUTSTATIC&nbsp;user$eval__4346.const__0&nbsp;:&nbsp;Lclojure</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Var;<br />
&nbsp;&nbsp;&nbsp;&nbsp;ICONST_1<br />
&nbsp;&nbsp;&nbsp;&nbsp;INVOKESTATIC&nbsp;java</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Integer.valueOf&nbsp;(I)Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Integer;<br />
&nbsp;&nbsp;&nbsp;&nbsp;PUTSTATIC&nbsp;user$eval__4346.const__1&nbsp;:&nbsp;Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Object;<br />
&nbsp;&nbsp;&nbsp;&nbsp;ICONST_2<br />
&nbsp;&nbsp;&nbsp;&nbsp;INVOKESTATIC&nbsp;java</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Integer.valueOf&nbsp;(I)Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Integer;<br />
&nbsp;&nbsp;&nbsp;&nbsp;PUTSTATIC&nbsp;user$eval__4346.const__2&nbsp;:&nbsp;Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Object;<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN<br />
&nbsp;&nbsp;&nbsp;&nbsp;MAXSTACK&nbsp;</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);">0</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;MAXLOCALS&nbsp;</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);">0</span><span style="color: rgb(0, 0, 0);"><br />
<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;access&nbsp;flags&nbsp;1</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);"><span style="background-color: yellow;"><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">init</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">()V</span></span></span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;L0<br />
&nbsp;&nbsp;&nbsp;&nbsp;LINENUMBER&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">&nbsp;L0<br />
&nbsp;&nbsp;&nbsp;L1<br />
&nbsp;&nbsp;&nbsp;&nbsp;ALOAD&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;INVOKESPECIAL&nbsp;clojure</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">AFunction.</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">init</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;()V<br />
&nbsp;&nbsp;&nbsp;L2<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN<br />
&nbsp;&nbsp;&nbsp;&nbsp;MAXSTACK&nbsp;</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);">0</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;MAXLOCALS&nbsp;</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);">0</span><span style="color: rgb(0, 0, 0);"><br />
<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;access&nbsp;flags&nbsp;1</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);"><span style="background-color: yellow;"><span style="color: rgb(0, 0, 0);">&nbsp;<strong>&nbsp;</strong></span><strong><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;invoke()Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Object;&nbsp;</span><span style="color: rgb(0, 0, 255);">throws</span><span style="color: rgb(0, 0, 0);">&nbsp;java</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span></strong><span style="color: rgb(0, 0, 0);"><strong>Exception</strong></span></span></span><span style="color: rgb(0, 0, 0);"><strong>&nbsp;</strong><br />
&nbsp;&nbsp;&nbsp;L0<br />
&nbsp;&nbsp;&nbsp;&nbsp;LINENUMBER&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">&nbsp;L0<br />
&nbsp;&nbsp;&nbsp;L1<br />
&nbsp;&nbsp;&nbsp;&nbsp;LINENUMBER&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">&nbsp;L1<br />
<span style="background-color: yellow;"><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;GETSTATIC&nbsp;user$eval__4346.const__1&nbsp;:&nbsp;Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Object;<br />
&nbsp;&nbsp;&nbsp;&nbsp;GETSTATIC&nbsp;user$eval__4346.const__2&nbsp;:&nbsp;Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Object;<br />
&nbsp;&nbsp;&nbsp;&nbsp;INVOKESTATIC&nbsp;clojure</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Numbers.add&nbsp;(Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Object;Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Object;)Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Number;</span></span></span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;L2<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOCALVARIABLE&nbsp;</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">&nbsp;Ljava</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">lang</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">Object;&nbsp;L0&nbsp;L2&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;ARETURN<br />
&nbsp;&nbsp;&nbsp;&nbsp;MAXSTACK&nbsp;</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);">0</span><span style="color: rgb(0, 0, 0);"><br />
&nbsp;&nbsp;&nbsp;&nbsp;MAXLOCALS&nbsp;</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);">0</span><span style="color: rgb(0, 0, 0);"><br />
}<br />
</span><span style="color: rgb(0, 0, 0);"><span style="background-color: yellow;">3</span></span></div>
<br />
３就是表达式的结果。可以看到，一个表达式生成了一个class。其中&lt;clinit&gt;是静态初始化块，主要是初始化表达式中的字面常量；&lt;init&gt;不用说，默认的构造函数；invoke是核心方法，表达式生成的class，new一个实例后调用的就是invoke方法，执行实际的代码,高亮部分加载了两个常量，并执行Number.add方法。<br />
<br />
最后，请Happy hacking!。<br />
<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/325775.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-07-11 12:07 <a href="http://www.blogjava.net/killme2008/archive/2010/07/11/325775.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>闭包使用的一个陷阱</title><link>http://www.blogjava.net/killme2008/archive/2010/07/09/325687.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 09 Jul 2010 15:52:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/07/09/325687.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/325687.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/07/09/325687.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/325687.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/325687.html</trackback:ping><description><![CDATA[<br />
来源：<a href="http://moonbase.rydia.net/mental/blog/programming/the-biggest-mistake-everyone-makes-with-closures.html">http://moonbase.rydia.net/mental/blog/programming/the-biggest-mistake-everyone-makes-with-closures.html</a><br />
<br />
看下面的Ruby代码<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">k&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[]<br />
</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;x&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">..</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
&nbsp;&nbsp;k.push(</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">&nbsp;{&nbsp;x&nbsp;})<br />
end</span></div>
<br />
执行<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">k[0].call</span></div>
<br />
你可能预期返回1，实际的结果却是3。这是为何？这是因为在<strong>迭代过程中共用了同一个context</strong>，导致k中的<strong>三个闭包都引用了同一个变量x</strong>。不仅仅Ruby有这个问题，python也一样<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">k&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">:&nbsp;x&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;x&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;xrange(</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">)]<br />
k[0]()<br />
</span></div>
<br />
Javascript同样如此<br />
<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">var&nbsp;k&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[];<br />
</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(var&nbsp;x&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;&nbsp;x&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">;&nbsp;x</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br />
&nbsp;&nbsp;k.push(function&nbsp;()&nbsp;{&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;x;&nbsp;});<br />
}<br />
alert(k[0]())</span></div>
<br />
<br />
解决这个问题很简单，就是将<strong>闭包包装到一个函数里，建立新的context</strong>，那么迭代过程中生成的闭包所处的context不同：<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;make_value_func(value)<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">&nbsp;{&nbsp;value&nbsp;}<br />
end<br />
k&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">1</span><span style="color: #000000;">..</span><span style="color: #000000;">3</span><span style="color: #000000;">).map&nbsp;{&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">x</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;make_value_func(x)&nbsp;}</span></div>
<br />
这个时候，k[0].call正确地返回1。<br />
<br />
这个问题并非在所有支持闭包的语言里都存在，例如scheme中就没有问题<br />
<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(define&nbsp;k&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">())</span><span style="color: #800000;"><br />
</span><span style="color: #000000;">(do&nbsp;((x&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;x&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;((</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;x&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">)&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">())</span><span style="color: #800000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;(set!&nbsp;k&nbsp;(cons&nbsp;(</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">&nbsp;()&nbsp;x)&nbsp;k)))<br />
(set!&nbsp;k&nbsp;(reverse&nbsp;k))<br />
<br />
((car&nbsp;k))&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">1</span></div>
<br />
<br />
Erlang也没有问题<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">K</span><span style="color: #000000;">=</span><span style="color: #000000;">[&nbsp;fun()</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">X&nbsp;end&nbsp;</span><span style="color: #000000;">||</span><span style="color: #000000;">&nbsp;X&nbsp;</span><span style="color: #000000;">&lt;-</span><span style="color: #000000;">&nbsp;[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">]].<br />
<br />
lists:map(fun(F)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;F()&nbsp;end,K). </span></div>
<br />
再试试Clojure:<br />
<div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(def&nbsp;k&nbsp;(</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;[i&nbsp;(range&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">)]&nbsp;(fn&nbsp;[]&nbsp;i)))<br />
(map&nbsp;#(</span><span style="color: #000000;">%</span><span style="color: #000000;">)&nbsp;k) </span></div>
<br />
同样没有问题。这里Erlang和Clojure都采用列表推断。<br />
<br />
<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/325687.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-07-09 23:52 <a href="http://www.blogjava.net/killme2008/archive/2010/07/09/325687.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><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>Actor、Coroutine和Continuation的概念澄清</title><link>http://www.blogjava.net/killme2008/archive/2010/03/23/316273.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 23 Mar 2010 03:49:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/03/23/316273.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/316273.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/03/23/316273.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/316273.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/316273.html</trackback:ping><description><![CDATA[<br />    Actor、<a href="http://en.wikipedia.org/wiki/Coroutine">Coroutine</a>和<a href="http://en.wikipedia.org/wiki/Continuation">Continuation</a>这三个概念由于并发的受关注而被经常提到，这里主要想谈下这三者的区别和联系，以便更好的区分问题领域和讨论。首先，Actor和Coroutine在我看来是两种并发模型，仅针对于并发这个领域，而Continuation则是程序设计领域的一个概念，相比于Actor和Coroutine是一个更基础的概念。<br /><br />    那么，什么是Continuation？这个要从表达式的求值说起。一个表达式的求值可以分为两个阶段：“<b>What to evaluate?</b>”和“<b>What to do with the value</b>”，“What to do with the value”就是计算的Continuation。以下面这段代码为例：<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, 255);">if</span><span style="color: rgb(0, 0, 0);"> x</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);"> then<br />   </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> x</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"><br />   </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> x<br />end</span></div><br />    考察其中的表达式x&lt;3，这个表达式就是“what to evaluate?”，代表你将计算的东西，然后根据x&lt;3的结果决定是执行x+1还是直接返回x，这个根据x&lt;3的值来决定下一步的过程就是这个表达式的Continuation，也就是"what to do with the value"。怎么得到某个表达式的Continuation呢？在支持Continuation的语言里提供了call-with-current-continuation的函数，通常简称为call/cc，使用这个函数你就可以在任何代码中得到Continuation。进一步，continuation有什么作用呢？它可以做的事情不少，如nonlocal exits、回溯、多任务的实现等等。例如在scheme中没有break语句，就可以用call/cc实现一些此类高级的控制结构：<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);">(call</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">cc (</span><span style="color: rgb(0, 0, 255);">lambda</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);">)<br />        (</span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">each (</span><span style="color: rgb(0, 0, 255);">lambda</span><span style="color: rgb(0, 0, 0);"> (x) (</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> x 0) (</span><span style="color: rgb(0, 0, 255);">break</span><span style="color: rgb(0, 0, 0);"> x)))<br />                </span><span style="color: rgb(128, 0, 0);">'</span><span style="color: rgb(128, 0, 0);">(99 88 -77 66 55))</span><span style="color: rgb(128, 0, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 128, 0);">#</span><span style="color: rgb(0, 128, 0);">t))</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);"><br /></span></div><br />    上面这段代码查找列表(99 88 -77 66 55)中的负数，当查找到的时候马上从迭代中退出并返回该值，其中的break就是一个continuation。刚才还提到continuation可以实现回溯，那么就可以实现一个穷举的机器出来用来搜索解空间，也就是类似Prolog中的回溯机制，在SICP这本书里就介绍了如何用call/cc实现一个简单的逻辑语言系统。更著名的就是神奇的amb操作符，有兴趣可以看看<a href="/killme2008/archive/2008/11/15/240672.html">这里</a>。<br />     <br />     接下来我们来看看如何continuation实现多任务，在Continuation的<a href="http://en.wikipedia.org/wiki/Continuation">维基百科</a>里给了一段代码来展示如何用scheme来实现coroutine，我稍微修改了下并添加了注释:<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);">;;continuation栈，保存了等待执行的continuation<br />(define call/cc call-with-current-continuation)<br />(define *queue* '())<br /><br />(define (empty-queue?)<br />        (null? *queue*))<br /><br />(define (enqueue x)<br />        (set! *queue* (append *queue* (list x))))<br /><br />(define (dequeue)<br />        (let ((x (car *queue*)))<br />              (set! *queue* (cdr *queue*))<br />         x))<br />;;启动协程<br />(define (resume proc)<br />       (call/cc<br />         (lambda (k)<br />           ;;保存当前continuation，执行proc<br />           (enqueue k)<br />           (proc))))<br />;;让出执行权<br />(define (yield)<br />     (call/cc<br />      (lambda (k)<br />         ;;保存当前continuation，弹出上一次执行的cont并执行<br />        (enqueue k)<br />        ((dequeue)))))<br />;;停止当前协程或者当没有一个协程时停止整个程序,最简单的调度程序<br />(define (thread-exit)<br />     (if (empty-queue?)<br />         (exit)<br />         ((dequeue))))<br /></span></div>（注：scheme以分号开头作为注释）<br /><br />     这其实就是一个coroutine的简单实现，context的保存、任务的调度、resume/yield原语……样样俱全。使用起来类似这样，下面这段程序轮流打印字符串：<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);">(define (display-str str)<br />        (lambda()<br />         (let loop()<br />              (display str)<br />              (newline)<br />              (yield)<br />              (loop))))<br /><br />;;;创建两个协程并启动调度器<br />(resume (display-str "This is AAA"))<br />(resume (display-str "Hello from BBB"))<br />(thread-exit)<br /></span></div><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);">This is AAA<br />Hello from BBB<br />This is AAA<br />Hello from BBB<br />This is AAA<br />Hello from BBB<br />This is AAA<br />Hello from BBB<br />……</span></div><br />    谈了这么多continuation的应用，事实上我想说明的是continuation可以用来实现协程，Ruby 1.9中call/cc和Fiber的实现（在cont.c)大体是一样的同样说明了这一点。<br /><br />     接下来我们讨论下Actor和Coroutine的关系，上面提到Actor是一种并发模型，我更愿意称之为一种编程风格，Actor跟message passing、Duck Typing是一脉相承的。Actor风格是可以这么描述：将物理世界抽象成一个一个的Actor，Actor之间通过发送消息相互通信，Actor不关心消息是否能被接收或者能否投递到，它只是简单地投递消息给其他actor，然后等待应答。Actor相比于Coroutine是一种更高层次的抽象，它提供的receive和pattern match的原语更接近于现实世界，而使用coroutine编程你还需要手工介入任务调度，这在Actor中是由一个调度器负责的。<br /><br />    同样，Actor可以用coroutine实现，例如Ruby有个<a href="http://revactor.org/">revactor</a>项目，就是利用1.9引入的Fiber实现actor风格的编程，它的实现非常简单，有兴趣地可以看看，其实跟continuation实现coroutine类似。但是Actor并不是一定要用coroutine才能实现，Actor是一种编程风格，你在Java、C#、C++中同样可以模拟这样的方式去做并发编程，.net社区的老赵<a href="http://www.cnblogs.com/JeffreyZhao/archive/2009/05/11/a-simple-actor-model-implementation.html">实现过一个简单的Actor</a>，<a href="http://www.scala-lang.org/">Scala</a>的Actor实现是基于外部库，利用scala强大的元编程能力使得库的使用像内置于语言。<br /><br />    总结下我想表达的：Continuation是程序设计领域的基础概念，它可以用于实现coroutine式的多任务，Actor是一种比之coroutine更为抽象的编程风格，Actor可以基于Coroutine实现但并非必须，Actor和Coroutine都是现在比较受关注的并发模型。<br /><br /><br /><br /><img src ="http://www.blogjava.net/killme2008/aggbug/316273.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-03-23 11:49 <a href="http://www.blogjava.net/killme2008/archive/2010/03/23/316273.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby Fiber指南（四）迭代器</title><link>http://www.blogjava.net/killme2008/archive/2010/03/12/315257.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 12 Mar 2010 04:48:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/03/12/315257.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/315257.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/03/12/315257.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/315257.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/315257.html</trackback:ping><description><![CDATA[<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;&nbsp; 上一节介绍了利用Fiber实现类unix管道风格的过滤链，这一节将介绍利用Fiber来实现迭代器，<span style="font-family: 宋体;">我们可以将循环的迭代器看作生产者</span><span lang="EN-US">-</span><span style="font-family: 宋体;">消费者模式的特殊的例子。迭代函数产生值给循环体消费。所以可以使用Fiber来实现迭代器。协程的一个关键特征是它可以不断颠倒调用者与被调用者之间的关系，这样我们毫无顾虑的使用它实现一个迭代器，而不用保存迭代函数返回的状态，也就是说无需在迭代函数中保存状态，状态的保存和恢复交由Fiber自动管理。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 这一节的介绍以一个例子贯穿前后，我们将不断演化这个例子，直到得到一个比较优雅的可重用的代码，这个例子就是求数组的全排列。如数组[1,2,3]的全排列包括6种排列：<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;">2</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">3</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">3</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">2</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
</span></div>
全排列的递归算法实现很简单，我们用Ruby实现如下：<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: #008000;">#</span><span style="color: #008000;">全排列的递归实现</span><span style="color: #008000;"><br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;permgen&nbsp;(a,&nbsp;n)<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;n&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;0&nbsp;then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printResult(a)<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n.times&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">i</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a[n</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">],&nbsp;a[i]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;a[i],&nbsp;a[n</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;permgen(a,&nbsp;n&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a[n</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">],&nbsp;a[i]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;a[i],&nbsp;a[n</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
end<br />
<br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;printResult&nbsp;(a)<br />
&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;a.join(</span><span style="color: #800000;">"</span><span style="color: #800000;">&nbsp;</span><span style="color: #800000;">"</span><span style="color: #000000;">)<br />
end<br />
<br />
permgen([</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">],</span><span style="color: #000000;">4</span><span style="color: #000000;">)<br />
</span></div>
算法的思路是这样：</span><span style="font-family: 宋体;">将数组中的每一个元素放到最后，依次递归生成所有剩余元素的排列</span>，没完成一个排列就打印出来。很显然，这里有消费者和生产者的关系存在，生产者负责产生排列，消费者负责打印任务，整个程序由消费者驱动，因此用Fiber改写如下：<br />
<br />
第一步，将打印任务修改为Fiber#yield，生产者产生一个排列后将结果传递给消费者并让出执行权：<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;">def</span><span style="color: #000000;">&nbsp;permgen&nbsp;(a,&nbsp;n)<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;n&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;0&nbsp;then<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">(a)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#8230;&#8230;<br />
end</span></div>
<br />
第二步，实现一个迭代器工厂，返回一个匿名的迭代函数，迭代函数请求Fiber产生一个新的排列：<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;">def</span><span style="color: #000000;">&nbsp;perm(a)<br />
&nbsp;&nbsp;f</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;permgen(a,a.size)<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">{&nbsp;f.resume&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;f.alive?&nbsp;}<br />
end<br />
</span></div>
<br />
这样一来我们就可以利用一个while循环来打印全排列：<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;">it</span><span style="color: #000000;">=</span><span style="color: #000000;">perm([</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">])<br />
<br />
</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;a</span><span style="color: #000000;">=</span><span style="color: #000000;">it.call<br />
&nbsp;&nbsp;&nbsp;printResult(a)<br />
end<br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 注意到，在perm方法中有一个很常见的模式，就是将对Fiber的resume封装在一个匿名函数内，在lua为了支持这种模式还特意提供了一个coroutine.wrap方法来方便编程，在Ruby Fiber中却没有，不过我们可以自己实现下，利用open-class的特性实现起来非常简单：<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: #008000;">#</span><span style="color: #008000;">为Fiber添加wrap方法</span><span style="color: #008000;"><br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Fiber<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;self.wrap<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;block_given?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do&nbsp;</span><span style="color: #000000;">|*</span><span style="color: #000000;">args</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">args<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">{</span><span style="color: #000000;">|*</span><span style="color: #000000;">args</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;f.resume(</span><span style="color: #000000;">*</span><span style="color: #000000;">args)&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;f.alive?&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;end<br />
end</span></div>
&nbsp;<br />
&nbsp;&nbsp;&nbsp; Fiber#wrap方法跟new方法一样，创建一个新的Fiber，但是返回的是一个匿名函数，这个匿名函数负责去调用fiber的resume，利用wrap改写perm方法变得更简洁：<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;">def</span><span style="color: #000000;">&nbsp;perm(a)<br />
&nbsp;&nbsp;Fiber.wrap{&nbsp;permgen(a,a.size)&nbsp;}<br />
end</span></div>
<br />
&nbsp;&nbsp;&nbsp; 但是还不够，while循环的方式还是不够优雅，每次都需要明确地调用迭代器的call方法，这一点让人挺不舒坦，如果能像for...in那样的泛型循环就好了，我们知道Ruby中的for...in其实是一个语法糖衣，都是转变成调用集合的each方法并传入处理的block，因此，要想实现一个优雅的迭代器，我们做下封装就好了：<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: #0000ff;">class</span><span style="color: #000000;">&nbsp;FiberIterator<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;initialize<br />
&nbsp;&nbsp;&nbsp;&nbsp;@fiber_wrap</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.wrap&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;end<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;each<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;value</span><span style="color: #000000;">=</span><span style="color: #000000;">@fiber_wrap.call<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">&nbsp;value<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;end<br />
end</span></div>
<br />
那么现在的perm方法变成了创建一个迭代器FiberIterator:<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;">def</span><span style="color: #000000;">&nbsp;perm(a)<br />
&nbsp;&nbsp;FiberIterator.new{&nbsp;permgen(a,a.size)&nbsp;}<br />
end</span></div>
这样一来我们就可以通过for...in来调用迭代器了<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;">it</span><span style="color: #000000;">=</span><span style="color: #000000;">perm([</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">])<br />
</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;a&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;it<br />
&nbsp;&nbsp;printResult(a)<br />
end</span></div>
<br />
<br />
<span style="font-family: 宋体;">&nbsp;&nbsp;&nbsp; <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
</span><img src ="http://www.blogjava.net/killme2008/aggbug/315257.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-03-12 12:48 <a href="http://www.blogjava.net/killme2008/archive/2010/03/12/315257.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby Fiber指南（三）过滤器</title><link>http://www.blogjava.net/killme2008/archive/2010/03/11/315215.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 11 Mar 2010 15:49:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/03/11/315215.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/315215.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/03/11/315215.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/315215.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/315215.html</trackback:ping><description><![CDATA[<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的基础知识之后，可以尝试用Fiber去做一些比较有趣的事情。这一节将讲述如何使用Fiber来实现类似unix系统中的管道功能。在unix系统中，可以通过管道将多个命令组合起来做一些强大的功能，最常用的例如查找所有的java进程：<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;">ps&nbsp;aux</span><span style="color: #000000;">|</span><span style="color: #000000;">grep&nbsp;java</span></div>
通过组合ps和grep命令来实现，ps的输出作为grep的输入，如果有更多的命令就形成了一条过滤链。过滤器本质上还是生产者和消费者模型，前一个过滤器产生结果，后一个过滤器消费这个结果并产生新的结果给下一个过滤器消费。因此我们就从最简单的生产者消费者模型实现说起。<br />
我们要展示的这个例子场景是这样：生产者从标准输入读入用户输入并发送给消费者，消费者打印这个输入，整个程序是由消费者驱动的，消费者唤醒生存者去读用户输入，生产者读到输入后让出执行权给消费者去打印，整个过程通过生产者和消费者的协作完成。<br />
生产者发送是通过yield返回用户输入给消费者(还记的上一节吗？）：<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: #0000ff;">def</span><span style="color: #000000;">&nbsp;send(x)<br />
&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">(x)<br />
end</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: #0000ff;">def</span><span style="color: #000000;">&nbsp;receive(prod)<br />
&nbsp;&nbsp;prod.resume<br />
end</span></div>
<br />
生产者是一个Fiber，它的任务就是等待用户输入并发送结果给消费者：<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;">def</span><span style="color: #000000;">&nbsp;producer()<br />
&nbsp;&nbsp;Fiber.new&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;true<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x</span><span style="color: #000000;">=</span><span style="color: #000000;">readline.chomp<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(x)<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;end<br />
end</span></div>
<br />
消费者负责驱动生产者，并且在接收到结果的时候打印，消费者是root fiber:<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;">def</span><span style="color: #000000;">&nbsp;consumer(producer)<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;true<br />
&nbsp;&nbsp;&nbsp;&nbsp;x</span><span style="color: #000000;">=</span><span style="color: #000000;">receive(producer)<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;x</span><span style="color: #000000;">==</span><span style="color: #800000;">'</span><span style="color: #800000;">quit</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;x<br />
&nbsp;&nbsp;end<br />
end</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;">consumer(producer())</span></div>
&nbsp;&nbsp; 完整的程序如下：<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: #008000;">#</span><span style="color: #008000;">生产者消费者</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">require&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">fiber</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
<br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;send(x)<br />
&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">(x)<br />
end<br />
<br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;receive(prod)<br />
&nbsp;&nbsp;prod.resume<br />
end<br />
<br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;producer()<br />
&nbsp;&nbsp;Fiber.new&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;true<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x</span><span style="color: #000000;">=</span><span style="color: #000000;">readline.chomp<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(x)<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;end<br />
end<br />
<br />
<br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;consumer(producer)<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;true<br />
&nbsp;&nbsp;&nbsp;&nbsp;x</span><span style="color: #000000;">=</span><span style="color: #000000;">receive(producer)<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;x</span><span style="color: #000000;">==</span><span style="color: #800000;">'</span><span style="color: #800000;">quit</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;x<br />
&nbsp;&nbsp;end<br />
end<br />
</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;$0</span><span style="color: #000000;">==</span><span style="color: #800080;">__FILE__</span><span style="color: #000000;"><br />
&nbsp;&nbsp;consumer(producer())<br />
end<br />
</span></div>
<br />
&nbsp;&nbsp; 读者可以尝试在ruby1.9下运行这个程序，每次程序都由消费者驱动生产者去等待用户输入，用户输入任何东西之后回车，生产者开始运行并将读到的结果发送给消费者并让出执行权（通过yield)，消费者在接收到yield返回的结果后打印这个结果，因此整个交互过程是一个echo的例子。<br />
<br />
最终的调用consumer(producer())已经有过滤器的影子在了，如果我们希望在producer和consumer之间插入其他过程对用户的输入做处理，也就是安插过滤器，那么新的过滤器也将作为fiber存在，新的fiber消费producer的输出，并输出新的结果给消费者，例如我们希望将用户的输入结果加上行号再打印，那么就插入一个称为filter的fiber:<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;">def</span><span style="color: #000000;">&nbsp;filter(prod)<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;Fiber.new&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;line</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;true<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value</span><span style="color: #000000;">=</span><span style="color: #000000;">receive(prod)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value</span><span style="color: #000000;">=</span><span style="color: #000000;">sprintf(</span><span style="color: #800000;">"</span><span style="color: #800000;">%5d&nbsp;%s</span><span style="color: #800000;">"</span><span style="color: #000000;">,line,value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;send(value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;line</span><span style="color: #000000;">=</span><span style="color: #000000;">line.succ<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;end<br />
end</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;">&nbsp;consumer(filter(producer()))</span></div>
&nbsp;&nbsp; 类似unix系统那样，简单的加入新的fiber组合起来就可以为打印结果添加行号。<br />
<br />
类似consumer(filter(producer()))的调用方式尽管已经很直观，但是我们还是希望能像unix系统那样调用，也就是通过竖线作为管道操作符：<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;">producer&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;filter&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;consumer</span></div>
这样的调用方式更将透明直观，清楚地表明整个过滤器链的运行过程。幸运的是在Ruby中支持对|方法符的重载，因此要实现这样的操作符并非难事,只要对Fiber做一层封装即可，下面给出的代码来自《Programming <a title="" href="http://www.ruby-lang.org">ruby</a>》的作者Dave Thomas的<a href="http://pragdave.blogs.pragprog.com/pragdave/2007/12/pipelines-using.html">blog</a>：<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: #0000ff;">class</span><span style="color: #000000;">&nbsp;PipelineElement<br />
&nbsp;&nbsp;&nbsp;attr_accessor&nbsp;:source<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;initialize<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@fiber_delegate&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Fiber.new&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;process<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">(other)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;other.source&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;self<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;other<br />
&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;resume<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@fiber_delegate.resume<br />
&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;process<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;value&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;input<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_value(value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;handle_value(value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output(value)<br />
&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;input<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@source.resume<br />
&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;output(value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">(value)<br />
&nbsp;&nbsp;&nbsp;end<br />
end<br />
</span></div>
<br />
这段代码非常巧妙，将Fiber和Ruby的功能展示的淋漓尽致。大致解说下，PipelineElement作为任何一个过滤器的父类，其中封装了一个fiber，这个fiber默认执行process，在process方法中可以看到上面生产者和消费者例子的影子，input类似receive方法调用前置过滤器(source)，output则将本过滤器处理的结果作为参数传递给yield并让出执行权，让这个过滤器的调用者（也就是后续过滤器）得到结果并继续处理。PipelineElement实现了&#8220;｜&#8221;方法，用于组合过滤器，将下一个过滤器的前置过滤器设置为本过滤器，并返回下一个过滤器。整个过滤链的驱动者是最后一个过滤器。<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: #0000ff;">class</span><span style="color: #000000;">&nbsp;Producer&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;PipelineElement<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;process<br />
&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;value</span><span style="color: #000000;">=</span><span style="color: #000000;">readline.chomp<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_value(value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;end<br />
end<br />
<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Filter&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;PipelineElement<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;initialize<br />
&nbsp;&nbsp;&nbsp;&nbsp;@line</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;super()<br />
&nbsp;&nbsp;end<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;handle_value(value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;value</span><span style="color: #000000;">=</span><span style="color: #000000;">sprintf(</span><span style="color: #800000;">"</span><span style="color: #800000;">%5d&nbsp;%s</span><span style="color: #800000;">"</span><span style="color: #000000;">,@line,value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;output(value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;@line</span><span style="color: #000000;">=</span><span style="color: #000000;">@line.succ<br />
&nbsp;&nbsp;end<br />
end<br />
<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Consumer&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;PipelineElement<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;handle_value(value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;value<br />
&nbsp;&nbsp;end<br />
end<br />
</span></div>
<br />
&nbsp;&nbsp; 现在的调用方式可以跟unix的管道很像了：<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;">producer</span><span style="color: #000000;">=</span><span style="color: #000000;">Producer.new<br />
filter</span><span style="color: #000000;">=</span><span style="color: #000000;">Filter.new<br />
consumer</span><span style="color: #000000;">=</span><span style="color: #000000;">Consumer.new<br />
<br />
<strong>pipeline&nbsp;</strong></span><strong><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;producer&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;filter&nbsp;</span><span style="color: #000000;">|</span></strong><span style="color: #000000;"><strong>&nbsp;consumer</strong><br />
pipeline.resume</span></div>
如果你打印pipeline对象，你将看到一条清晰的过滤链,<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: #008000;">#</span><span style="color: #008000;">&lt;Consumer:0x8f08bf4&nbsp;@fiber_delegate=#&lt;Fiber:0x8f08a88&gt;,&nbsp;@source=#&lt;Filter:0x8f08db4&nbsp;@line=1,&nbsp;@fiber_delegate=#&lt;Fiber:0x8f08d60&gt;,&nbsp;@source=#&lt;Producer:0x8f09054&nbsp;@fiber_delegate=#&lt;Fiber:0x8f09038&gt;&gt;&gt;&gt;</span><span style="color: #008000;"><br />
</span></div>
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/315215.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-03-11 23:49 <a href="http://www.blogjava.net/killme2008/archive/2010/03/11/315215.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby Fiber指南（二）参数传递</title><link>http://www.blogjava.net/killme2008/archive/2010/03/11/315197.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 11 Mar 2010 10:41:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/03/11/315197.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/315197.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/03/11/315197.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/315197.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/315197.html</trackback:ping><description><![CDATA[<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编程的基础篇，只不过参数传递算是一个比较重要的主题，因此独立一节。参数传递发生在两个Fiber之间，作为Fiber之间通讯的一个主要手段。<br />
<br />
&nbsp;&nbsp;&nbsp; 首先，我们可以通过resume调用给Fiber的block传递参数:<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: #008080;">1</span>&nbsp;<span style="color: #008000;">#</span><span style="color: #008000;">resume传递参数给fiber</span><span style="color: #008000;"><br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">f</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b,c</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;p&nbsp;a,b,c<br />
</span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">end<br />
</span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">6</span>&nbsp;<span style="color: #000000;">f.resume(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">7</span>&nbsp;</div>
<br />
这个例子展示了怎么向fiber的block传递参数，f这个fiber简单地将传入的参数打印出来并终止。<br />
<br />
&nbsp;&nbsp;&nbsp; 其次，Fiber#yield也可以传递参数给调用resume作为返回结果，猜猜下面的代码打印什么？<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: #008080;">1</span>&nbsp;<span style="color: #008000;">#</span><span style="color: #008000;">yield传递参数给resume</span><span style="color: #008000;"><br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">f</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">&nbsp;a</span><span style="color: #000000;">+</span><span style="color: #000000;">b,a</span><span style="color: #000000;">-</span><span style="color: #000000;">b<br />
&nbsp;&nbsp;&nbsp; p a,b<br />
</span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">end<br />
</span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">6</span>&nbsp;<span style="color: #000000;">p&nbsp;f.resume(</span><span style="color: #000000;">10</span><span style="color: #000000;">,</span><span style="color: #000000;">10</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">7</span>&nbsp;<span style="color: #000000;">p&nbsp;f.resume(</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">8</span>&nbsp;</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;">20</span><span style="color: #000000;">,&nbsp;0]<br />
10<br />
10<br />
[</span><span style="color: #000000;">10</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;">]<br />
</span></div>
让我们分析下代码的执行过程：<br />
1、第6行第一次调用resume，传入10,10两个参数<br />
2、f开始执行任务，它的任务是调用Fiber#yield，并将参数相加和相减的结果作为参数给yield，也就是执行Fiber.yield 20,10<br />
3、f调用yield之后挂起，返回root fiber，yield的两个参数10、20作为返回结果打印。<br />
4、第7行代码，root fiber再次调用resume并传入参数，f被切入并执行代码p a,b，打印a、b，a和b仍然是上次调用保存的10，而非resume传入的3和4。<br />
5、f执行完毕，返回p a,b的结果作为resume结果，也就是[10,10]<br />
<br />
&nbsp;&nbsp;&nbsp; 刚才看到上面yield向resume传递参数的例子中第二次调用resume的参数3和4被忽略了，事实上如果还存在一次yield调用，那么3和4将被作为yield的返回结果使用，这就是我们接下来将看到的，通过resume调用传递参数作为fiber中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: #008080;">1</span>&nbsp;<span style="color: #008000;">#</span><span style="color: #008000;">resume传递参数给yield</span><span style="color: #008000;"><br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">f</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do<br />
</span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">end<br />
</span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">6</span>&nbsp;<span style="color: #000000;">p&nbsp;f.resume(</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">7</span>&nbsp;<span style="color: #000000;">p&nbsp;f.resume(</span><span style="color: #000000;">2</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">8</span>&nbsp;</div>
<br />
这次的打印结果将是：<br />
<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><span style="color: #000000;">nil<br />
</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
</span></div>
&nbsp;&nbsp; 第一次调用resume传入的1将被忽略，因为f的block不需要参数，然后f执行1 + Fiber.yield，在yield的挂起，加法运算没有继续，因为yield的调用没有参数，因此第一次resume返回nil；第二次resume调用传入2，这时候2将作为Fiber#yield的调用结果跟1相加,完成加法运算，得到的结果就是3，这个结果作为fiber的返回值返回给调用者。<br />
<br />
&nbsp;&nbsp;&nbsp; 总结下上面我们谈到的四种传递参数的情形：通过resume向fiber的block传递参数、通过yield向调用者传递参数、通过resume向yield传递参数、fiber返回值传递给调用者。<br />
&nbsp;&nbsp;&nbsp; <br /><img src ="http://www.blogjava.net/killme2008/aggbug/315197.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-03-11 18:41 <a href="http://www.blogjava.net/killme2008/archive/2010/03/11/315197.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby Fiber指南（一）基础</title><link>http://www.blogjava.net/killme2008/archive/2010/03/11/315158.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 11 Mar 2010 04:53:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/03/11/315158.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/315158.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/03/11/315158.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/315158.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/315158.html</trackback:ping><description><![CDATA[<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 />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 这是一个Ruby Fiber的教程，基本是按照《Programming in lua》中讲述协程章节的顺序来介绍Ruby Fiber的，初步分为5节：基础、参数传递、过滤器、迭代器、应用。这是第一节，介绍下Ruby Fiber的基础知识。<br />
<br />
<a title="" href="http://www.ruby-lang.org">&nbsp;&nbsp;&nbsp; Ruby</a> 1.9引入了Fiber，通常称为纤程，事实上跟传统的coroutine——协程是一个概念，一种非抢占式的多线程模型。所谓非抢占式就是当一个协程运行的时候，你不能在外部终止它，而只能等待这个协程主动（一般是yield）让出执行权给其他协程,通过协作来达到多任务并发的目的。协程的优点在于由于全部都是用户空间内的操作，因此它是非常轻量级的，占用的资源很小，并且context的切换效率也非常高效（可以看看<a href="/killme2008/archive/2010/03/02/314264.html">这个测试</a>），在编程模型上能简化对阻塞操作或者异步调用的使用，使得涉及到此类操作的代码变的非常直观和优雅；缺点在于容错和健壮性上需要做更多工作，如果某个协程阻塞了，可能导致整个系统挂住，无法充分利用多核优势，有一定的学习使用曲线。<br />
&nbsp;&nbsp; 上面都是场面话，先看看代码怎么写吧，比如我们写一个打印hello的协程：<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: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">require&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">fiber</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">f</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do<br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;p&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">hello</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">end<br />
</span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">p&nbsp;f.alive?<br />
</span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">f.resume<br />
</span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">p&nbsp;f.alive?<br />
</span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">f.resume<br />
</span><span style="color: #008080;">11</span></div>
&nbsp;&nbsp;&nbsp; 附注：这里的代码都在ruby1.9.1-p378测试通过。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 第一行先引入fiber库，事实上fiber库并不是必须的，这里是为了调用Fiber#alive?方法才引入。然后通过Fiber#new创建一个Fiber，Fiber#new接受一个block，block里就是这个Fiber将要执行的任务。Fiber#alive?用来判断Fiber是否存活，一个Fiber有三种状态：Created、Running、Terminated，分别表示创建完成、执行、终止，处于Created或者Running状态的时候Fiber#alive?都返回true。启动Fiber是通过Fiber#resume方法，这个Fiber将进入Running状态，打印"hello"并终止。当一个Fiber终止后，如果你再次调用resume将抛出异常，告诉你这个Fiber已经寿终正寝了。因此上面的程序输出是：<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;">0<br />
</span><span style="color: #800000;">"</span><span style="color: #800000;">hello</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
false<br />
fiber1.rb:</span><span style="color: #000000;">10</span><span style="color: #000000;">:</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;`resume</span><span style="color: #800000;">'</span><span style="color: #800000;">:&nbsp;dead&nbsp;fiber&nbsp;called&nbsp;(FiberError)</span><span style="color: #800000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">from</span><span style="color: #000000;">&nbsp;fiber1.rb:</span><span style="color: #000000;">10</span><span style="color: #000000;">:</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;`</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">main</span><span style="color: #000000;">&gt;</span><span style="color: #800000;">'</span></div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 眼尖的已经注意到了，这里alive?返回是0，而不是true，这是1.9.1这个版本的<a href="http://redmine.ruby-lang.org/issues/show/1547">一个BUG</a>，1.9.2返回的就是true。不过在Ruby里,除了nil和false，其他都是true。<br />
<br />
&nbsp;&nbsp;&nbsp; 刚才提到，我们为了调用Fiber#alive?而引入了fiber库，Fiber其实是内置于语言的，并不需要引入额外的库，fiber库对Fiber的功能做了增强，具体可以先看看它的<a href="http://ruby-doc.org/core-1.9/classes/Fiber.html">文档</a>，主要是引入了几个方法：Fiber#current返回当前协程，Fiber#alive?判断Fiber是否存活，最重要的是Fiber#transfer方法，这个方法使得Ruby的Fiber支持所谓全对称协程（<span lang="EN-US">symmetric coroutines），默认的resume/yield(yield后面会看到）是半对称的协程（</span><span lang="EN-US">asymmetric coroutines</span><span style="font-family: 宋体;">），这两种模型的区别在于</span><span style="font-family: 宋体;">&#8220;<strong>挂起一个正在执行的协同函数</strong>&#8221;与&#8220;<strong>使一个被挂起的协同再次执行的函数</strong>&#8221;是不是<strong>同一个</strong>。在这里就是Fiber#transfer一个方法做了resume/yield两个方法所做的事情</span>。全对称协程就可以从一个协程切换到任意其他协程，而半对称则要通过调用者来中转。但是Ruby Fiber的调用不能跨线程（thread，注意跟fiber区分），只能在同一个thread内进行切换,看下面代码：<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: #008080;">1</span>&nbsp;<span style="color: #000000;">f&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;nil<br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">Thread.new&nbsp;do<br />
</span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;f&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Fiber.new{}<br />
</span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">end.join<br />
</span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;">f.resume</span></div>
<br />
f在线程内创建，在线程外调用，这样的调用在Ruby 1.9里是不允许的，执行的结果将抛出异常<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;">fiber_thread.rb:</span><span style="color: #000000;">5</span><span style="color: #000000;">:</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;`resume</span><span style="color: #800000;">'</span><span style="color: #800000;">:&nbsp;fiber&nbsp;called&nbsp;across&nbsp;threads (FiberError)</span><span style="color: #800000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">from</span><span style="color: #000000;">&nbsp;fiber_thread.rb:</span><span style="color: #000000;">5</span><span style="color: #000000;">:</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;`</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">main</span><span style="color: #000000;">&gt;</span><span style="color: #800000;">'<br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 刚才我们仅仅使用了resume，那么yield是干什么的呢？resume是使一个挂起的协程执行，那么yield就是让一个正在执行的Fiber挂起并将执行权交给它的调用者，yield只能在某个Fiber任务内调用，不能在root Fiber调用，程序的主进程就是一个root fiber,如果你在root fiber执行一个Fiber.yield，也将抛出异常：<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;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
FiberError:&nbsp;can</span><span style="color: #800000;">'</span><span style="color: #800000;">t&nbsp;yield&nbsp;from&nbsp;root&nbsp;fiber</span></div>
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 看一个resume结合yield的例子：<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: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">f</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do<br />
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;p&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;p&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;p&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">end<br />
</span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">f.resume&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;打印1</span><span style="color: #008000;"><br />
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">f.resume&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;打印2</span><span style="color: #008000;"><br />
</span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">f.resume&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;打印3</span></div>
<br />
&nbsp;&nbsp; f是一个Fiber，它的任务就是打印1,2,3，第一次调用resume时，f在打印1之后调用了Fiber.yield，f将让出执行权给它的调用者（这里就是root fiber)并挂起，然后root fiber再次调用f.resume，那么将从上次挂起的地方继续执行——打印2，又调用Fiber.yield再次挂起，最后一次f.resume执行后续的打印任务并终止f。<br />
<br />
&nbsp;&nbsp;&nbsp; Fiber#yield跟语言中的yield关键字是不同的，block中的yield也有&#8220;让出&#8221;的意思，<strike>但是这是在同一个context里，而Fiber#yield让出就切换到另一个context去了，这是完全不同的。</strike>block的yield其实是匿名函数的语法糖衣，它是切换context的，跟Fiber不同的是，它不保留上一次调用的context，这个可以通过一个例子来区分：<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: #008080;">1</span>&nbsp;<span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;test<br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;">end<br />
</span><span style="color: #008080;">6</span>&nbsp;<span style="color: #000000;">test{x&nbsp;</span><span style="color: #000000;">||=</span><span style="color: #000000;">&nbsp;0;&nbsp;puts&nbsp;x</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">}<br />
</span><span style="color: #008080;">7</span>&nbsp;</div>
这里的test方法接受一个block，三次调用yield让block执行，block里先是初始化x=0，然后每次调用加1，你期望打印什么？<br />
答案是:<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><span style="color: #000000;">1</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">1</span></div>
这个结果刚好证明了yield是不保留上一次调用的context，每次x都是重新初始化为0并加上1，因此打印的都是1。让我们使用Fiber写同一个例子：<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: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">fiber</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do<br />
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;x</span><span style="color: #000000;">||=</span><span style="color: #000000;">0<br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;puts&nbsp;x</span><span style="color: #000000;">+=</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;puts&nbsp;x</span><span style="color: #000000;">+=</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;puts&nbsp;x</span><span style="color: #000000;">+=</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;Fiber.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">end<br />
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">fiber.resume<br />
</span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">fiber.resume<br />
</span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">fiber.resume<br />
</span><span style="color: #008080;">14</span>&nbsp;</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;">1</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">2</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">3</span></div>
这次能符合预期地打印1，2，3，说明Fiber的每次挂起都将当前的context保存起来，留待下次resume的时候恢复执行。因此关键字yield是无法实现Fiber的，fiber其实跟continuation相关，在底层fiber跟callcc的实现是一致的（cont.c)。<br />
<br />
&nbsp;&nbsp;&nbsp; Fiber#current返回当前执行的fiber，如果你在root fiber中调用Fiber.current返回的就是当前的root fiber，一个小例子：<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: #008080;">1</span>&nbsp;<span style="color: #000000;">require&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">fiber</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">2</span>&nbsp;<span style="color: #000000;">f</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do<br />
</span><span style="color: #008080;">3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;p&nbsp;Fiber.current<br />
</span><span style="color: #008080;">4</span>&nbsp;<span style="color: #000000;">end<br />
</span><span style="color: #008080;">5</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">6</span>&nbsp;<span style="color: #000000;">p&nbsp;Fiber.current<br />
</span><span style="color: #008080;">7</span>&nbsp;<span style="color: #000000;">f.resume</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: #008000;">#</span><span style="color: #008000;">&lt;Fiber:0x9bf89f4&gt;</span><span style="color: #008000;"><br />
#</span><span style="color: #008000;">&lt;Fiber:0x9bf8a2c&gt;</span></div>
表明root fiber跟f是两个不同的Fiber。<br />
&nbsp; &nbsp;&nbsp; <br />
&nbsp; &nbsp;&nbsp; 基础的东西基本讲完了，最后看看Fiber#transfer的简单例子,两个协程协作来打印&#8220;hello world&#8221;：<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: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">require&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">fiber</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">f1</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">other</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">print</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">hello</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;other.transfer<br />
</span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">end<br />
</span><span style="color: #008080;">&nbsp;7</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;8</span>&nbsp;<span style="color: #000000;">f2</span><span style="color: #000000;">=</span><span style="color: #000000;">Fiber.new&nbsp;do</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">&nbsp;9</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">print</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">&nbsp;world\n</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">10</span>&nbsp;<span style="color: #000000;">end<br />
</span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">f1.resume(f2) <br />
</span></div>
<br />
通过这个例子还可以学到一点，resume可以传递参数，参数将作为Fiber的block的参数，参数传递将是下一节的主题。<br />
<br />
<br />
&nbsp;&nbsp;&nbsp; <br /><img src ="http://www.blogjava.net/killme2008/aggbug/315158.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-03-11 12:53 <a href="http://www.blogjava.net/killme2008/archive/2010/03/11/315158.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lua、LuaJIT Coroutine和Ruby Fiber的切换效率对比</title><link>http://www.blogjava.net/killme2008/archive/2010/03/02/314264.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 02 Mar 2010 03:50:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/03/02/314264.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/314264.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/03/02/314264.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/314264.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/314264.html</trackback:ping><description><![CDATA[最近重读了《Programming Lua》，对协程做了重点复习。众所周知，Ruby1.9引入了Fiber，同样是coroutine，不过Ruby Fiber支持全对称协程（通过fiber库)，而Lua只支持所谓半对称协程。<br /><br />
    这里将对Lua、LuaJIT和Ruby Fiber的切换效率做个对比测试，测试场景很简单：两个coroutine相互切换达到5000万次，统计每秒切换的次数,各测试多次取最佳。<br /><br />
    lua的程序如下：<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);">c1</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">coroutine</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">create(function ()<br />
                     </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> true </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"><br />
                       coroutine</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">yield()<br />
                     end<br />
                    end)<br /><br />
c2</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">coroutine</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">create(function ()<br />
                     </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> true </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"><br />
                       coroutine</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">yield()<br />
                     end<br />
                    end)<br /><br /></span><span style="color: rgb(0, 0, 255);">local</span><span style="color: rgb(0, 0, 0);"> start</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">os</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">clock()<br /></span><span style="color: rgb(0, 0, 255);">local</span><span style="color: rgb(0, 0, 0);"> count</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(128, 0, 0);">50000000</span><span style="color: rgb(0, 0, 0);"><br /><br /></span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);"> i</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);">count </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"><br />
 coroutine</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">resume(c1)<br />
 coroutine</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">resume(c2)<br />
end<br /><br /></span><span style="color: rgb(0, 0, 255);">print</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(128, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">count</span><span style="color: rgb(0, 0, 0);">/</span><span style="color: rgb(0, 0, 0);">(os</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">clock()</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">start))<br /></span></div><br />
    考虑到在循环中事实上发生了四次切换：main-&gt;c1,c1-&gt;main,main-&gt;c2,c2-&gt;main，因此乘以4。<br /><br />
    <a title="" href="http://www.ruby-lang.org">Ruby</a> Fiber的测试分两种,采用transfer的例程如下：<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, 255);">require</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;">fiber</span><span style="color: rgb(0, 0, 0); font-weight: bold;">'</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">require</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;">benchmark</span><span style="color: rgb(0, 0, 0); font-weight: bold;">'</span><span style="color: rgb(0, 0, 0);"><br /><br />
Benchmark</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">bm </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">x</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);"><br />
  MAX_COUNT</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(128, 0, 0);">50000000</span><span style="color: rgb(0, 0, 0);"><br />
  f1</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">Fiber</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">new </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">other</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">count</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);"><br />
     </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> count</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">MAX_COUNT<br />
      other</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">count</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">other</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">transfer(Fiber</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">current</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">count</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">succ)<br />
     end<br />
  end<br /><br />
  f2</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">Fiber</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">new </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">other</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">count</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);"><br />
    </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> count</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">MAX_COUNT<br />
      other</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">count</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">other</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">transfer(Fiber</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">current</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">count</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">succ)<br />
    end<br />
  end<br /><br />
  x</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">report{<br />
    f1</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">resume(f2</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);">)<br />
  }<br />
end<br /></span></div>
     <a title="" href="http://www.ruby-lang.org">Ruby</a> Fiber采用resume/yield的例程如下：<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, 255);">require</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;">benchmark</span><span style="color: rgb(0, 0, 0); font-weight: bold;">'</span><span style="color: rgb(0, 0, 0);"><br />
f1</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">Fiber</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">new </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"><br />
  </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> true<br />
    Fiber</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">yield<br />
  end<br />
end<br />
f2</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">Fiber</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">new </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"><br />
  </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> true<br />
    Fiber</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">yield<br />
  end<br />
end<br /><br />
COUNT</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(128, 0, 0);">50000000</span><span style="color: rgb(0, 0, 0);"><br /><br />
Benchmark</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">bm </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">x</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);"><br />
  x</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">report{<br />
     COUNT</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 255);">times</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);"><br />
         f1</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">resume<br />
         f2</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">resume<br />
     end<br />
  }<br />
end<br /></span></div><br /><br /><br />
     测试环境：<br />
          CPU :    Intel(R) Core(TM)2 Duo CPU     P8600  @ 2.40GHz<br />
          Memory:  3GB<br />
          System :  Linux dennis-laptop 2.6.31-14-generic #48-Ubuntu SMP<br />
          Lua    : 5.1.4<br />
          <a title="" href="http://www.ruby-lang.org">ruby</a>  :  1.9.1p378<br />
          LuaJIT:  1.1.5和2.0.0-beta2<br /><br />
      测试结果如下：<br />
    
<table style="border: 1px solid ; font-weight: bold;" cellpadding="2" cellspacing="2" height="96" width="911" border="0"><tbody><tr><td> </td><td> Lua</td><td> LuaJIT 1.1.5<br /></td><td> LuaJIT 2.0.0-beta2<br /></td><td> <a title="" href="http://www.ruby-lang.org">ruby</a>-transfer<br /></td><td> <a title="" href="http://www.ruby-lang.org">ruby</a>-resume/yield</td></tr><tr><td> 次数</td><td> 6123698</td><td> 9354536</td><td> 24875620</td><td> 825491</td><td> 969649</td></tr></tbody></table><br /><br />
      结论：<br />
      1、lua的协程切换效率都是百万级别，luaJIT 2.0的性能更是牛叉，切换效率是原生lua的4倍，达到千万级别。<br />
      2、相形之下,Ruby Fiber的效率比较差了，十万级别。<br />
      3、Ruby使用transfer的效率比之resume/yield略差那么一点，排除一些测试误差，两者应该是差不多的，从ruby源码上看resume/yield和transfer的调用是一样的，resume还多了几条指令。<br />
      4、额外信息，Ruby Fiber和lua coroutine都只能跑在一个cpu上，这个测试肯定能跑满一个cpu，内存占用上，lua也比ruby小很多。<br />
 <br /><br /><img src ="http://www.blogjava.net/killme2008/aggbug/314264.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-03-02 11:50 <a href="http://www.blogjava.net/killme2008/archive/2010/03/02/314264.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby Tip：定义索引操作符</title><link>http://www.blogjava.net/killme2008/archive/2010/02/01/311523.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 01 Feb 2010 08:29:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/02/01/311523.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/311523.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/02/01/311523.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/311523.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/311523.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 怎么让你对象跟Array或者Hash一样，可以使用[ ]操作符来获取属性值或者赋值？ 问题其实就是如何定义<strong>index</strong>操作符，在Ruby中可以这样做：<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: #0000ff;">class</span><span style="color: #000000;">&nbsp;Message<br />
&nbsp;&nbsp;&nbsp;def&nbsp;initialize<br />
&nbsp;&nbsp;&nbsp;&nbsp;@props</span><span style="color: #000000;">=</span><span style="color: #000000;">Hash.</span><span style="color: #0000ff;">new</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;def&nbsp;[](key)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@props[key]<br />
&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;def&nbsp;[]</span><span style="color: #000000;">=</span><span style="color: #000000;">(key,value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@props[key]</span><span style="color: #000000;">=</span><span style="color: #000000;">value<br />
&nbsp;&nbsp;&nbsp;end&nbsp;<br />
end<br />
<br />
m</span><span style="color: #000000;">=</span><span style="color: #000000;">Message.</span><span style="color: #0000ff;">new</span><span style="color: #000000;"><br />
<br />
m[</span><span style="color: #000000;">0</span><span style="color: #000000;">]</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
p&nbsp;m[</span><span style="color: #000000;">0</span><span style="color: #000000;">]<br />
<br />
m[:a]</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">hello</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
p&nbsp;m[:a]</span></div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意方法签名。<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/311523.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-02-01 16:29 <a href="http://www.blogjava.net/killme2008/archive/2010/02/01/311523.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>amb解决排列组合问题</title><link>http://www.blogjava.net/killme2008/archive/2009/10/19/298820.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 19 Oct 2009 03:37:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2009/10/19/298820.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/298820.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2009/10/19/298820.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/298820.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/298820.html</trackback:ping><description><![CDATA[&nbsp; 看到这么一个题目：<br />
&nbsp;&nbsp;&nbsp; {3,2,2,6,7,8}排序输出,7不在第二位,68不在一起。<br />
&nbsp; <br />
&nbsp; 这样的题目似乎避免不了遍历，关键还在于过滤条件的安排，怎么让过滤的范围尽量地小。通常的做法是循环遍历，对于类似Prolog这样的语言来说，由于内置了推理引擎，可以简单地描述问题，让引擎来帮你做递归遍历，解决这类问题是非常简单的。Prolog好久没写，以Ruby的amb操作符为例来解决这道题目：<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: #008000;">#</span><span style="color: #008000;">结果为hash，去重</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">$hash</span><span style="color: #000000;">=</span><span style="color: #000000;">{}<br />
amb</span><span style="color: #000000;">=</span><span style="color: #000000;">Amb.new<br />
array</span><span style="color: #000000;">=</span><span style="color: #000000;">[</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">6</span><span style="color: #000000;">,</span><span style="color: #000000;">7</span><span style="color: #000000;">,</span><span style="color: #000000;">8</span><span style="color: #000000;">]<br />
</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;array<br />
&nbsp;alias&nbsp;remove&nbsp;delete<br />
&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;delete(</span><span style="color: #000000;">*</span><span style="color: #000000;">nums)<br />
&nbsp;&nbsp;&nbsp;result</span><span style="color: #000000;">=</span><span style="color: #000000;">dup<br />
&nbsp;&nbsp;&nbsp;nums.each&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">n</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;result.delete_at(result.index(n))&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;result.index(n)<br />
&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;result<br />
&nbsp;end<br />
end<br />
</span><span style="color: #008000;">#</span><span style="color: #008000;">从集合选元素</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">one</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">array)<br />
two</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">(array.delete(one)))<br />
three</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">(array.delete(one,two)))<br />
four</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">(array.delete(one,two,three)))<br />
five</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">(array.delete(one,two,three,four)))<br />
six</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">(array.delete(one,two,three,four,five)))<br />
<br />
</span><span style="color: #008000;">#</span><span style="color: #008000;">条件1：第二个位置不能是7</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">amb.require(two</span><span style="color: #000000;">!=</span><span style="color: #000000;">7</span><span style="color: #000000;">)<br />
</span><span style="color: #008000;">#</span><span style="color: #008000;">条件2：6跟8不能一起出现</span><span style="color: #008000;"><br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;six_eight_not_join(a,b)<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">#{a}#{b}</span><span style="color: #800000;">"</span><span style="color: #000000;">!=</span><span style="color: #800000;">"</span><span style="color: #800000;">68</span><span style="color: #800000;">"</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #800000;">"</span><span style="color: #800000;">#{a}#{b}</span><span style="color: #800000;">"</span><span style="color: #000000;">!=</span><span style="color: #800000;">"</span><span style="color: #800000;">86</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
end<br />
amb.require(six_eight_not_join(one,two))<br />
amb.require(six_eight_not_join(two,three))<br />
amb.require(six_eight_not_join(three,four))<br />
amb.require(six_eight_not_join(four,five))<br />
amb.require(six_eight_not_join(five,six))<br />
<br />
</span><span style="color: #008000;">#</span><span style="color: #008000;">条件3：不重复,利用全局hash判断</span><span style="color: #008000;"><br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;distinct?(one,two,three,four,five,six)<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;$hash[</span><span style="color: #800000;">"</span><span style="color: #800000;">#{one},#{two},#{three},#{four},#{five},#{six}</span><span style="color: #800000;">"</span><span style="color: #000000;">].nil?<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$hash[</span><span style="color: #800000;">"</span><span style="color: #800000;">#{one},#{two},#{three},#{four},#{five},#{six}</span><span style="color: #800000;">"</span><span style="color: #000000;">]</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">&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;true<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;false<br />
&nbsp;&nbsp;end<br />
end<br />
amb.require(distinct?(one,two,three,four,five,six))<br />
puts&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">#{one},#{two},#{three},#{four},#{five},#{six}</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
amb.failure</span></div>
<br />
<br />
&nbsp;&nbsp; 三个条件的满足通过amb.require来设置，这里安排的只是一种顺序，可以根据实际测试结果来安排这些条件的顺序以最大程度地提高效率。代码注释很清楚了，我就不多嘴了。Ruby amb的实现可以看<a href="http://www.blogjava.net/killme2008/archive/2008/11/15/240672.html">这里</a>。什么是amb可以看<a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.55.8479">这个</a>。<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/298820.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-10-19 11:37 <a href="http://www.blogjava.net/killme2008/archive/2009/10/19/298820.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Scheme的字符串操作</title><link>http://www.blogjava.net/killme2008/archive/2009/10/12/297947.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 12 Oct 2009 09:59:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2009/10/12/297947.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/297947.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2009/10/12/297947.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/297947.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/297947.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 字符串操作是任何一门编程语言中最常用的操作之一，scheme也提供了一系列procudure来操作字符串。<br />
<br />
1、字符串的比较，有6个，分别是string=?&nbsp; string&gt;? string&lt;? string&gt;=? string&lt;=?<br />
<br />
这与其他语言中对string的比较并无不同，比较字符和长度。<br />
<br />
例子：<br />
(string=? "mom" "mom")&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;#t<br />
(string&lt;? "mom" "mommy")&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;#t<br />
(string&gt;? "Dad" "Dad")&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;#f<br />
(string=? "Mom and Dad" "mom and dad")&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;#f<br />
(string&lt;? "a" "b" "c")&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;#t<br />
<br />
注意这些比较操作是大小写敏感。相应的，大小写不敏感的版本：<br />
<br />
<span class="formdef"><strong>procedure</strong>: (string-ci=?&nbsp;<em>string<sub>1</sub></em>&nbsp;<em>string<sub>2</sub></em>&nbsp;<em>string<sub>3</sub></em>&nbsp;...)</span>
<br />
<span class="formdef"><strong>procedure</strong>: (string-ci&lt;?&nbsp;<em>string<sub>1</sub></em>&nbsp;<em>string<sub>2</sub></em>&nbsp;<em>string<sub>3</sub></em>&nbsp;...)</span>
<br />
<span class="formdef"><strong>procedure</strong>: (string-ci&gt;?&nbsp;<em>string<sub>1</sub></em>&nbsp;<em>string<sub>2</sub></em>&nbsp;<em>string<sub>3</sub></em>&nbsp;...)</span>
<br />
<span class="formdef"><strong>procedure</strong>: (string-ci&lt;=?&nbsp;<em>string<sub>1</sub></em>&nbsp;<em>string<sub>2</sub></em>&nbsp;<em>string<sub>3</sub></em>&nbsp;...)</span>
<br />
<span class="formdef"><strong>procedure</strong>: (string-ci&gt;=?&nbsp;<em>string<sub>1</sub></em>&nbsp;<em>string<sub>2</sub></em>&nbsp;<em>string<sub>3</sub></em>&nbsp;...)</span>
<br />
<br />
2、从字符构造字符串，使用string过程<br />
(string #\a)&nbsp; =&gt; "a"<br />
(string #\a #\b #\c)&nbsp; =&gt; "abc"<br />
<br />
注意，换行字符是#\newline,回车字符是#\return<br />
<br />
3、重复N个字符构造字符串<br />
(make-string)&nbsp; =&gt; ""<br />
(make-string 4 #\a)&nbsp; =&gt;"aaaa")<br />
<br />
4、字符串长度 string-length<br />
(string-length "") =&gt;0<br />
(string-length "dennis") =&gt; 6<br />
<br />
5、取第N个字符，相当于java中的charAt：<br />
<br />
(string-ref "hi there" 0)&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;#\h<br />
(string-ref "hi there" 5)&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;#\e<br />
<br />
6、修改字符串的第N个字符：<br />
(string-set! "hello" 0 #\H) =&gt; "Hello"<br />
<br />
7、拷贝字符串：<br />
(let ((str "abc"))<br />
&nbsp; (eq? str (string-copy str)))&nbsp; =&gt; #f<br />
(let ((str "abc"))<br />
&nbsp; (equal? str (string-copy str)))&nbsp; =&gt; #t<br />
<br />
8、拼接字符串，string-append<br />
(string-append) =&gt; ""<br />
(string-append "abc" "defg") =&gt; "abcdefg"<br />
<br />
9、截取子串<br />
(substring "hi there" 0&nbsp;1)&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;"h"<br />
(substring "hi there" 3&nbsp;6)&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;"the"<br />
(substring "hi there" 5&nbsp;5)&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;""
<br />
<br />
10、填充字符串<br />
(let ((str (string-copy "sleepy")))<br />
&nbsp;&nbsp;(string-fill! str #\Z)<br />
&nbsp;&nbsp;str)&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;"ZZZZZZ"<br />
<br />
11、与list的相互转换<br />
<br />
(string-&gt;list "")&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;()<br />
(string-&gt;list "abc")&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;(#\a #\b #\c)<br />
<br />
(list-&gt;string '())&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;""<br />
(list-&gt;string '(#\a #\b #\c))&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;"abc"<br />
(list-&gt;string<br />
&nbsp;&nbsp;(map char-upcase<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(string-&gt;list "abc")))&nbsp;<img src="http://www.scheme.com/tspl3/math/tspl/0.gif" alt="&lt;graphic&gt;" />&nbsp;"ABC"<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/297947.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-10-12 17:59 <a href="http://www.blogjava.net/killme2008/archive/2009/10/12/297947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Scala Ring Benchmark</title><link>http://www.blogjava.net/killme2008/archive/2009/06/09/280904.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 09 Jun 2009 05:42:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2009/06/09/280904.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/280904.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2009/06/09/280904.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/280904.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/280904.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; Scala实现的ring benchmark：<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: #0000ff;">import</span><span style="color: #000000;">&nbsp;scala.actors.Actor<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;scala.actors.Actor._<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.concurrent.CountDownLatch<br />
</span><span style="color: #0000ff;">case</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Message()<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Process(m:Int,p:Actor,latch:CountDownLatch)&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;Actor{<br />
&nbsp;&nbsp;var&nbsp;next</span><span style="color: #000000;">=</span><span style="color: #000000;">p<br />
&nbsp;&nbsp;def&nbsp;act{<br />
&nbsp;&nbsp;&nbsp;loop{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;recvAndSend(m)<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;def&nbsp;recvAndSend(count:Int){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(count</span><span style="color: #000000;">==</span><span style="color: #000000;">0</span><span style="color: #000000;">){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;latch.countDown()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;react{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">case</span><span style="color: #000000;">&nbsp;Message()</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next</span><span style="color: #000000;">!</span><span style="color: #000000;">&nbsp;Message()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;recvAndSend(count</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
object&nbsp;RingBenchmark{<br />
&nbsp;&nbsp;def&nbsp;main(args:Array[String]){<br />
&nbsp;&nbsp;&nbsp;&nbsp;start(args(</span><span style="color: #000000;">0</span><span style="color: #000000;">).toInt,args(</span><span style="color: #000000;">1</span><span style="color: #000000;">).toInt)&nbsp;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;def&nbsp;start(n:Int,m:Int){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val&nbsp;latch</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;CountDownLatch(n)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val&nbsp;first</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Process(m,</span><span style="color: #0000ff;">null</span><span style="color: #000000;">,latch)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val&nbsp;p</span><span style="color: #000000;">=</span><span style="color: #000000;">createProcess(first,n</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">,m,latch)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;first.next</span><span style="color: #000000;">=</span><span style="color: #000000;">p<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val&nbsp;start:Long</span><span style="color: #000000;">=</span><span style="color: #000000;">System.currentTimeMillis<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;first.start<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;first</span><span style="color: #000000;">!</span><span style="color: #000000;">Message()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;latch.await()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;println(System.currentTimeMillis</span><span style="color: #000000;">-</span><span style="color: #000000;">start)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;def&nbsp;createProcess(p:Actor,n:Int,m:Int,latch:CountDownLatch):Actor</span><span style="color: #000000;">=</span><span style="color: #000000;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(n</span><span style="color: #000000;">==</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val&nbsp;next</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Process(m,p,latch)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next.start<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;createProcess(next,n</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">,m,latch)<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
}</span></div>
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 与Erlang版本的比较（单位毫秒),scala版本2.7.4-final，erlang是R13B, windows xp<br />
<br />
<table style="width: 378px; height: 82px;" border="0" cellpadding="2" cellspacing="2">
    <tbody>
        <tr>
            <td>&nbsp;N</td>
            <td>&nbsp;M</td>
            <td>&nbsp;Scala</td>
            <td>&nbsp;Erlang</td>
        </tr>
        <tr>
            <td>&nbsp;1000</td>
            <td>&nbsp;100</td>
            <td>&nbsp;297</td>
            <td>&nbsp;62</td>
        </tr>
        <tr>
            <td>&nbsp;1000</td>
            <td>&nbsp;500</td>
            <td>&nbsp;1328</td>
            <td>&nbsp;343</td>
        </tr>
        <tr align="left" valign="middle">
            <td>&nbsp;1000</td>
            <td>&nbsp;1000</td>
            <td>&nbsp;2469</td>
            <td>&nbsp;671</td>
        </tr>
        <tr align="left" valign="middle">
            <td>&nbsp;10000</td>
            <td>&nbsp;100</td>
            <td>&nbsp;2812</td>
            <td>&nbsp;781</td>
        </tr>
        <tr align="left" valign="middle">
            <td>&nbsp;10000</td>
            <td>&nbsp;1000</td>
            <td>&nbsp;28796</td>
            <td>&nbsp;7797</td>
        </tr>
    </tbody>
</table>
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/280904.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-06-09 13:42 <a href="http://www.blogjava.net/killme2008/archive/2009/06/09/280904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于Object.object_id方法</title><link>http://www.blogjava.net/killme2008/archive/2009/05/24/277664.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 24 May 2009 04:46:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2009/05/24/277664.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/277664.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2009/05/24/277664.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/277664.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/277664.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; Ruby中的Object.object_id是返回一个Fixnum类型的标识符来代表一个对象。没有两个active的对象的object_id是一样的，如：<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;">a</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">1.8.6</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
b</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">1.8.6</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
a.object_id&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">24393910</span><span style="color: #000000;"><br />
b.object_id&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">24390830</span></div>
&nbsp;&nbsp;&nbsp; 尽管a==b，然而两者的object_id是不同。<br />
&nbsp;&nbsp;&nbsp; 但是这里有两种例外情况，对于常量，哪怕你将它赋给不同的变量，它们的object_id是一样的：<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;">a</span><span style="color: #000000;">=</span><span style="color: #000000;">RUBY_VERSION<br />
b</span><span style="color: #000000;">=</span><span style="color: #000000;">RUBY_VERSION<br />
a.object_id&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">21628310</span><span style="color: #000000;"><br />
b.object_id&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">21628310<br />
<br />
C="hello"&nbsp; <br />
a=C&nbsp; <br />
b=C&nbsp; <br />
a.object_id =&gt;&nbsp; 24243480&nbsp; <br />
b.object_id =&gt;&nbsp; 24243480&nbsp; <br />
</span></div>
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 除此之外，对于symbol类型，返回的也将是同一个object_id：<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;">a</span><span style="color: #000000;">=</span><span style="color: #000000;">:name<br />
b</span><span style="color: #000000;">=</span><span style="color: #000000;">:name<br />
a.object_id&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">34258</span><span style="color: #000000;"><br />
b.object_id&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">34258</span><span style="color: #000000;"><br />
</span></div>
&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;">VALUE<br />
rb_obj_id(VALUE&nbsp;obj)<br />
{<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(TYPE(obj)&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;T_SYMBOL)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;(SYM2ID(obj)&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;sizeof(RVALUE)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">4</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">))&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;FIXNUM_FLAG;<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(SPECIAL_CONST_P(obj))&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;LONG2NUM((</span><span style="color: #0000ff;">long</span><span style="color: #000000;">)obj);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;(VALUE)((</span><span style="color: #0000ff;">long</span><span style="color: #000000;">)obj</span><span style="color: #000000;">|</span><span style="color: #000000;">FIXNUM_FLAG);<br />
}</span></div>
&nbsp;&nbsp;&nbsp; Object.object_id方法对这两种情况做了特殊处理，常量和symbol都应当是唯一的。<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/277664.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-05-24 12:46 <a href="http://www.blogjava.net/killme2008/archive/2009/05/24/277664.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>scheme中文编程</title><link>http://www.blogjava.net/killme2008/archive/2009/03/20/261142.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 20 Mar 2009 15:27:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2009/03/20/261142.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/261142.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2009/03/20/261142.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/261142.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/261142.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;&nbsp; 受javaeye上的《Ruby中文编程》启发，帖子中有人提到如果if这样的关键字都可以定义成中文，那就是真正的中文编程。那时我就想到，这个其实要在scheme中实现是多么简单，将sicp书中的解释器稍微修改下就可以了，只要修改解析的部分即可。解释器的完整代码放后面，我们先看看有趣的例子：Code highlighting produced by A...&nbsp;&nbsp;<a href='http://www.blogjava.net/killme2008/archive/2009/03/20/261142.html'>阅读全文</a><img src ="http://www.blogjava.net/killme2008/aggbug/261142.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-03-20 23:27 <a href="http://www.blogjava.net/killme2008/archive/2009/03/20/261142.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>安装配置Emacs-rails</title><link>http://www.blogjava.net/killme2008/archive/2008/11/23/242067.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 22 Nov 2008 18:22:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/11/23/242067.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/242067.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/11/23/242067.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/242067.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/242067.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 首先你的机器上肯定要安装emacs啦，此步略过不表。<br />
&nbsp;1、从 http://rubyforge.org/projects/emacs-rails 下载最新emacs-rails，解压文件到~/.emacs.d/rails 目录<br />
&nbsp;2、根据README，你需要下载三个依赖库：<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;">cd&nbsp;</span><span style="color: #000000;">~/</span><span style="color: #000000;">.emacs.d</span><span style="color: #000000;">/</span><span style="color: #000000;">rails<br />
wget&nbsp;http:</span><span style="color: #000000;">//</span><span style="color: #000000;">www.kazmier.com</span><span style="color: #000000;">/</span><span style="color: #000000;">computer</span><span style="color: #000000;">/</span><span style="color: #000000;">snippet.el<br />
wget&nbsp;http:</span><span style="color: #000000;">//</span><span style="color: #000000;">www.webweavertech.com</span><span style="color: #000000;">/</span><span style="color: #000000;">ovidiu</span><span style="color: #000000;">/</span><span style="color: #000000;">emacs</span><span style="color: #000000;">/</span><span style="color: #000000;">find</span><span style="color: #000000;">-</span><span style="color: #000000;">recursive.txt<br />
mv&nbsp;find</span><span style="color: #000000;">-</span><span style="color: #000000;">recursive.txt&nbsp;find</span><span style="color: #000000;">-</span><span style="color: #000000;">recursive.el<br />
<br />
wget&nbsp;http:</span><span style="color: #000000;">//</span><span style="color: #000000;">svn.ruby</span><span style="color: #000000;">-</span><span style="color: #000000;">lang.org</span><span style="color: #000000;">/</span><span style="color: #000000;">cgi</span><span style="color: #000000;">-</span><span style="color: #000000;">bin</span><span style="color: #000000;">/</span><span style="color: #000000;">viewvc.cgi</span><span style="color: #000000;">/</span><span style="color: #000000;">trunk</span><span style="color: #000000;">/</span><span style="color: #000000;">misc</span><span style="color: #000000;">/</span><span style="color: #000000;">inf</span><span style="color: #000000;">-</span><span style="color: #000000;"><a title="" href="http://www.ruby-lang.org" >ruby</a>.el?view</span><span style="color: #000000;">=</span><span style="color: #000000;">co<br />
mv&nbsp;inf</span><span style="color: #000000;">-</span><span style="color: #000000;"><a title="" href="http://www.ruby-lang.org" >ruby</a>.el\?view</span><span style="color: #000000;">=</span><span style="color: #000000;">co&nbsp;inf</span><span style="color: #000000;">-</span><span style="color: #000000;"><a title="" href="http://www.ruby-lang.org" >ruby</a>.el</span></div>
<br />
3、将ruby源代码目录下的/misc子目录中的emacs扩展文件拷贝到/usr/share/emacs/site-lisp/目录下：<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;">sudo&nbsp;cp&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">home</span><span style="color: #000000;">/</span><span style="color: #000000;">dennis</span><span style="color: #000000;">/</span><span style="color: #000000;">backup</span><span style="color: #000000;">/</span><span style="color: #000000;"><a title="" href="http://www.ruby-lang.org" >ruby</a></span><span style="color: #000000;">-</span><span style="color: #000000;">1.8</span><span style="color: #000000;">.</span><span style="color: #000000;">7</span><span style="color: #000000;">-</span><span style="color: #000000;">p72</span><span style="color: #000000;">/</span><span style="color: #000000;">misc</span><span style="color: #000000;">/*</span><span style="color: #000000;">.el&nbsp;</span><span style="color: #000000;">/</span><span style="color: #000000;">usr</span><span style="color: #000000;">/</span><span style="color: #000000;">share</span><span style="color: #000000;">/</span><span style="color: #000000;">emacs</span><span style="color: #000000;">/</span><span style="color: #000000;">site</span><span style="color: #000000;">-</span><span style="color: #000000;">lisp</span><span style="color: #000000;">/</span><span style="color: #000000;"><br />
</span></div>
<br />
4、在~/.emacs添加两行代码，加载emacs-rails<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;">(setq&nbsp;load</span><span style="color: #000000;">-</span><span style="color: #000000;">path&nbsp;(cons&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">~/.emacs.d/rails</span><span style="color: #800000;">"</span><span style="color: #000000;">&nbsp;load</span><span style="color: #000000;">-</span><span style="color: #000000;">path))<br />
(require&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">rails)</span></div>
<br />
&nbsp;&nbsp;&nbsp; 搞定，看起来挺强悍的，在菜单兰多了个ROR菜单，需要熟悉下快捷键。<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/242067.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> 2008-11-23 02:22 <a href="http://www.blogjava.net/killme2008/archive/2008/11/23/242067.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ubuntu下解决Ruby安装后缺少openssl的问题</title><link>http://www.blogjava.net/killme2008/archive/2008/11/23/242066.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 22 Nov 2008 17:34:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/11/23/242066.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/242066.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/11/23/242066.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/242066.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/242066.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 一开始尝试使用<br />
&nbsp;&nbsp;&nbsp; sudo apt-get install libopenssl-ruby1.8<br />
&nbsp;&nbsp;&nbsp; 安装是安装成功了，但是仍然提示找不到openssl。还是决定从源码安装，首先确保ubuntu安装了openssl：<br />
&nbsp;&nbsp;&nbsp; sudo apt-get install openssl<br />
&nbsp;&nbsp;&nbsp; sudo apt-get install libssl-dev<br />
&nbsp;&nbsp;&nbsp; sudo apt-get install libssl0.9.8<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 然后进入ruby源码目录下的/ext/openssl<br />
&nbsp;&nbsp;&nbsp; cd RUBY_SOURCE/ext/openssl<br />
&nbsp;&nbsp;&nbsp; <a title="" href="http://www.ruby-lang.org" >ruby</a> extconf.rb<br />
&nbsp;&nbsp;&nbsp; make <br />
&nbsp;&nbsp;&nbsp; sudo make install<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/242066.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> 2008-11-23 01:34 <a href="http://www.blogjava.net/killme2008/archive/2008/11/23/242066.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>sicp 4.4.1小节习题</title><link>http://www.blogjava.net/killme2008/archive/2008/11/22/241931.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 22 Nov 2008 05:27:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/11/22/241931.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/241931.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/11/22/241931.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/241931.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/241931.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;&nbsp; 本节开始进入第4章最后一部分——逻辑程序设计。scheme将实现一种查询语言，非常类似prolog。由于解释器的实现在后面，还未读到，前面的习题我都将用prolog做测试，当然也给出scheme版本的解答，待以后测试。&nbsp;&nbsp;&nbsp; 首先给出依照书中所述写出的prolog事实库：Code highlighting prod...&nbsp;&nbsp;<a href='http://www.blogjava.net/killme2008/archive/2008/11/22/241931.html'>阅读全文</a><img src ="http://www.blogjava.net/killme2008/aggbug/241931.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> 2008-11-22 13:27 <a href="http://www.blogjava.net/killme2008/archive/2008/11/22/241931.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用Ruby amb解决说谎者谜题</title><link>http://www.blogjava.net/killme2008/archive/2008/11/15/240672.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 15 Nov 2008 10:50:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/11/15/240672.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/240672.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/11/15/240672.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/240672.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/240672.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 说谎者谜题是sicp4.3.2小节的一道题目，题目本身不难：<br />
五个女生参加一个考试，她们的家长对考试结果过分关注。为此她们约定，在给家里写信谈到考试的时候，每个姑娘都要写一句真话和一句假话。下面是从她们的信里摘抄出来的句子：<br />
Betty : kitty考第二，我只考了第三<br />
Ethel : 你们应该很高兴听到我考了第一，joan第二<br />
joan :&nbsp;&nbsp; 我考第三，可怜的Ethel垫底<br />
kitty:&nbsp; 我第二，marry只考了第四<br />
marry: 我是第四，Betty的成绩最高。<br />
这五个姑娘的实际排名是什么？<br />
<br />
&nbsp;&nbsp;&nbsp; Ruby本来就有call/cc，因此也可以实现amb操作符，网上已经有一个实现了：<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;Amb<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;ExhaustedError&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;RuntimeError;&nbsp;end<br />
&nbsp;&nbsp;def&nbsp;initialize<br />
&nbsp;&nbsp;&nbsp;&nbsp;@fail&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;proc&nbsp;{&nbsp;fail&nbsp;ExhaustedError,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">amb&nbsp;tree&nbsp;exhausted</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;}<br />
&nbsp;&nbsp;end<br />
&nbsp;&nbsp;def&nbsp;choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">choices)<br />
&nbsp;&nbsp;&nbsp;&nbsp;prev_fail&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;@fail<br />
&nbsp;&nbsp;&nbsp;&nbsp;callcc&nbsp;{&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">sk</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;choices.each&nbsp;{&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">choice</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;callcc&nbsp;{&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">fk</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@fail&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;proc&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@fail&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;prev_fail<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fk.call(:fail)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;choice.respond_to</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;:call<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sk.call(choice.call)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;sk.call(choice)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@fail.call<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;end<br />
&nbsp;&nbsp;def&nbsp;failure<br />
&nbsp;&nbsp;&nbsp;&nbsp;choose<br />
&nbsp;&nbsp;end<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;def&nbsp;</span><span style="color: #0000ff;">assert</span><span style="color: #000000;">(cond)<br />
&nbsp;&nbsp;&nbsp;&nbsp;failure&nbsp;unless&nbsp;cond<br />
&nbsp;&nbsp;end<br />
&nbsp;&nbsp;alias&nbsp;:require&nbsp;:</span><span style="color: #0000ff;">assert</span><span style="color: #000000;"><br />
end<br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 这一段代码与scheme宏实现amb是完全相同的：<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;amb</span><span style="color: #000000;">-</span><span style="color: #000000;">fail&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">*)</span><span style="color: #800000;"><br />
</span><span style="color: #000000;"><br />
(define&nbsp;initialize</span><span style="color: #000000;">-</span><span style="color: #000000;">amb</span><span style="color: #000000;">-</span><span style="color: #000000;">fail<br />
&nbsp;&nbsp;(</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">&nbsp;()<br />
&nbsp;&nbsp;&nbsp;&nbsp;(set!&nbsp;amb</span><span style="color: #000000;">-</span><span style="color: #000000;">fail<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">&nbsp;()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(error&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">amb&nbsp;tree&nbsp;exhausted</span><span style="color: #800000;">"</span><span style="color: #000000;">)))))<br />
<br />
(initialize</span><span style="color: #000000;">-</span><span style="color: #000000;">amb</span><span style="color: #000000;">-</span><span style="color: #000000;">fail)<br />
(define&nbsp;call</span><span style="color: #000000;">/</span><span style="color: #000000;">cc&nbsp;call</span><span style="color: #000000;">-</span><span style="color: #000000;">with</span><span style="color: #000000;">-</span><span style="color: #000000;">current</span><span style="color: #000000;">-</span><span style="color: #000000;">continuation)<br />
(define</span><span style="color: #000000;">-</span><span style="color: #000000;">syntax&nbsp;amb<br />
&nbsp;&nbsp;(syntax</span><span style="color: #000000;">-</span><span style="color: #000000;">rules&nbsp;()<br />
&nbsp;&nbsp;&nbsp;&nbsp;((amb&nbsp;alt&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" />)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;((prev</span><span style="color: #000000;">-</span><span style="color: #000000;">amb</span><span style="color: #000000;">-</span><span style="color: #000000;">fail&nbsp;amb</span><span style="color: #000000;">-</span><span style="color: #000000;">fail))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(call</span><span style="color: #000000;">/</span><span style="color: #000000;">cc<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">&nbsp;(sk)<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(call</span><span style="color: #000000;">/</span><span style="color: #000000;">cc<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">&nbsp;(fk)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(set!&nbsp;amb</span><span style="color: #000000;">-</span><span style="color: #000000;">fail<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">&nbsp;()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(set!&nbsp;amb</span><span style="color: #000000;">-</span><span style="color: #000000;">fail&nbsp;prev</span><span style="color: #000000;">-</span><span style="color: #000000;">amb</span><span style="color: #000000;">-</span><span style="color: #000000;">fail)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fk&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">fail)))</span><span style="color: #800000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(sk&nbsp;alt)))&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><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;(prev</span><span style="color: #000000;">-</span><span style="color: #000000;">amb</span><span style="color: #000000;">-</span><span style="color: #000000;">fail)))))))</span></div>
&nbsp;&nbsp;&nbsp; 回到谜题，从题意可知每个姑娘的两句话的异或结果为true，并且姑娘的排名肯定不会相同，因此定义两个辅助过程：<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;">require&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">amb</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;distinct?(items)<br />
&nbsp;&nbsp;items.uniq</span><span style="color: #000000;">==</span><span style="color: #000000;">items<br />
end<br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;xor(exp1,exp2)<br />
&nbsp;(exp1&nbsp;</span><span style="color: #0000ff;">or</span><span style="color: #000000;">&nbsp;exp2)&nbsp;</span><span style="color: #0000ff;">and</span><span style="color: #000000;">&nbsp;!(exp1&nbsp;</span><span style="color: #0000ff;">and</span><span style="color: #000000;">&nbsp;exp2)<br />
end</span></div>
&nbsp;&nbsp;&nbsp; 剩下的完全就是将题目翻译成代码即可了，没有多少可以解释的东西：<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;">amb</span><span style="color: #000000;">=</span><span style="color: #000000;">Amb.new<br />
betty</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">])<br />
ethel</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">])<br />
joan</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">])<br />
kitty</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">])<br />
marry</span><span style="color: #000000;">=</span><span style="color: #000000;">amb.choose(</span><span style="color: #000000;">*</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">])<br />
<br />
amb.require(xor(kitty</span><span style="color: #000000;">==</span><span style="color: #000000;">2</span><span style="color: #000000;">,betty</span><span style="color: #000000;">==</span><span style="color: #000000;">3</span><span style="color: #000000;">))<br />
amb.require(xor(ethel</span><span style="color: #000000;">==</span><span style="color: #000000;">1</span><span style="color: #000000;">,joan</span><span style="color: #000000;">==</span><span style="color: #000000;">2</span><span style="color: #000000;">))<br />
amb.require(xor(joan</span><span style="color: #000000;">==</span><span style="color: #000000;">3</span><span style="color: #000000;">,ethel</span><span style="color: #000000;">==</span><span style="color: #000000;">5</span><span style="color: #000000;">))<br />
amb.require(xor(kitty</span><span style="color: #000000;">==</span><span style="color: #000000;">2</span><span style="color: #000000;">,marry</span><span style="color: #000000;">==</span><span style="color: #000000;">4</span><span style="color: #000000;">))<br />
amb.require(xor(marry</span><span style="color: #000000;">==</span><span style="color: #000000;">4</span><span style="color: #000000;">,betty</span><span style="color: #000000;">==</span><span style="color: #000000;">1</span><span style="color: #000000;">))<br />
amb.require(distinct?([betty,ethel,joan,kitty,marry]))<br />
puts&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">betty:#{betty}&nbsp;ethel:#{ethel}&nbsp;joan:#{joan}&nbsp;kitty:#{kitty}&nbsp;marry:#{marry}</span><span style="color: #800000;">"</span></div>
<br />
&nbsp;&nbsp;&nbsp; 答案就是：<br />
&nbsp;&nbsp;&nbsp; <strong>betty:3 ethel:5 joan:2 kitty:1 marry:4&nbsp;</strong>&nbsp; <br />
<br />
&nbsp;&nbsp;&nbsp; 最后给出一个Prolog的解答：<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;">notmember(A,[]).<br />
notmember(A,[B</span><span style="color: #000000;">|</span><span style="color: #000000;">L]):</span><span style="color: #000000;">-</span><span style="color: #000000;"><br />
&nbsp;&nbsp;A\</span><span style="color: #000000;">==</span><span style="color: #000000;">B,<br />
&nbsp;&nbsp;notmember(A,L).<br />
distinct([A,B,C,D,E]):</span><span style="color: #000000;">-</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;notmember(A,[B,C,D,E]),<br />
&nbsp;&nbsp;&nbsp;notmember(B,[A,C,D,E]),<br />
&nbsp;&nbsp;&nbsp;notmember(C,[A,B,D,E]),<br />
&nbsp;&nbsp;&nbsp;notmember(D,[A,B,C,E]),<br />
&nbsp;&nbsp;&nbsp;notmember(E,[A,B,C,D]).<br />
xor(Exp1,Exp2):</span><span style="color: #000000;">-</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;(Exp1;Exp2),\</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;(Exp1,Exp2).<br />
solve(Betty,Ethel,Joan,Kitty,Marry):</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;X</span><span style="color: #000000;">=</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">],<br />
&nbsp;&nbsp;&nbsp;member(Betty,X),<br />
&nbsp;&nbsp;&nbsp;member(Ethel,X),<br />
&nbsp;&nbsp;&nbsp;member(Joan,X),<br />
&nbsp;&nbsp;&nbsp;member(Kitty,X),<br />
&nbsp;&nbsp;&nbsp;member(Marry,X),<br />
&nbsp;&nbsp;&nbsp;distinct([Betty,Ethel,Joan,Kitty,Marry]),<br />
&nbsp;&nbsp;&nbsp;xor(Kitty</span><span style="color: #000000;">=</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">2</span><span style="color: #000000;">,Betty</span><span style="color: #000000;">=</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">3</span><span style="color: #000000;">),<br />
&nbsp;&nbsp;&nbsp;xor(Ethel</span><span style="color: #000000;">=</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">,Joan</span><span style="color: #000000;">=</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">2</span><span style="color: #000000;">),<br />
&nbsp;&nbsp;&nbsp;xor(Joan</span><span style="color: #000000;">=</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">3</span><span style="color: #000000;">,Ethel</span><span style="color: #000000;">=</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">5</span><span style="color: #000000;">),<br />
&nbsp;&nbsp;&nbsp;xor(Kitty</span><span style="color: #000000;">=</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">2</span><span style="color: #000000;">,Marry</span><span style="color: #000000;">=</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">4</span><span style="color: #000000;">),<br />
&nbsp;&nbsp;&nbsp;xor(Marry</span><span style="color: #000000;">=</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">4</span><span style="color: #000000;">,Betty</span><span style="color: #000000;">=</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">).</span></div>
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/240672.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> 2008-11-15 18:50 <a href="http://www.blogjava.net/killme2008/archive/2008/11/15/240672.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>降低JRuby的内存占用的可能方法</title><link>http://www.blogjava.net/killme2008/archive/2008/11/15/240621.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 14 Nov 2008 16:58:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/11/15/240621.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/240621.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/11/15/240621.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/240621.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/240621.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; JRuby的内存占用是比较高的，毕竟需要启动一个JVM以及构建抽象语法树等，一般同一个脚本的内存占用都是CRuby的几十倍甚至上百倍。记的Infoq上有过一个新闻是说sun跟东京某大学合作研究Ruby和JRuby的MVM，可以在几个VM之间共享解释器，可以在启动多个VM的时候大大降低内存占用。不过这个项目暂时没有什么消息，要想在实际中应用更是没影的事情。有无其他解决办法？今天看到IBM Developer的一篇文章，原来IBM JRE for the Java platform SE 5早就引入了类共享的特性，也就是说允许通过缓存在 JVM 之间共享类来减少内存占用和重复加载类的开销。最新SR1 jvm更是引入了AOT编译的原生代码也可以放入共享缓存。那么，如果用ibm的支持类共享的VM来跑多个JRuby进程，会不会能大大减少整体的内存占用情况呢？可能出现的两个问题：<br />
1、兼容性，IBM的jvm跑sun的JRuby，还是可能出现兼容性的问题。<br />
2、JRuby的jar包中的类能否被共享？JRuby生成的语法树、Ruby运行时等能不能被共享？<br />
<br />
有兴趣的童鞋可以测试一下，我的机器是AMD的，ibm jvm装不了，还是我下错了？<br />
&nbsp;&nbsp;&nbsp; <br /><img src ="http://www.blogjava.net/killme2008/aggbug/240621.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> 2008-11-15 00:58 <a href="http://www.blogjava.net/killme2008/archive/2008/11/15/240621.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>swfheader 0.10 Released（已更正下载地址）</title><link>http://www.blogjava.net/killme2008/archive/2008/10/11/233785.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 11 Oct 2008 15:38:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/10/11/233785.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/233785.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/10/11/233785.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/233785.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/233785.html</trackback:ping><description><![CDATA[update:俺确实够愚蠢了，竟然打包错了。半夜打包的，看来真有点头昏。非常抱歉，已经更正下载地址。<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; swfheader是一个处理swf文件的工具脚本，可用于读取swf文件头信息、压缩和解压缩swf文件。很早以前发布过一个0.01版。最近复审了代码，发现了一个愚蠢的读二进制文件错误导致没办法正确的解压或者压缩swf文件。今天更正了此bug，重构了部分代码并做了更多测试，已经可以正常使用。<br />
<br />
项目地址:<br />
<a href="http://code.google.com/p/swf-util/">http://code.google.com/p/swf-util/</a><br />
项目描述：<br />
&nbsp; 一个轻量级的纯Ruby实现的swf文件处理脚本，可以读取swf文件头信息（大小、帧率、长宽、是否压缩、flash版本信息等）、压缩swf文件和解压缩swf文件。基于Apache License2协议发布。<br />
<br />
<br />
示例<br />
下载<a href="http://swf-util.googlecode.com/files/swfheader0.10.zip">swfheader0.10.zip</a>后，解压后有README文件和swfheader-0.10.gem，通过<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;">gem&nbsp;install&nbsp;&nbsp;swfheader</span><span style="color: #000000;">-</span><span style="color: #000000;">0.10</span><span style="color: #000000;">.gem</span></div>
命令安装swfheader即可使用。<br />
<br />
1、读文件头信息：<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;">require&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">swfheader</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
header</span><span style="color: #000000;">=</span><span style="color: #000000;">SwfUtil::read_header(</span><span style="color: #800000;">"</span><span style="color: #800000;">c:/test.swf</span><span style="color: #800000;">"</span><span style="color: #000000;">))<br />
header.signature&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;标志字符&nbsp;CWS表示压缩的swf文件，FWS表示未压缩的</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">header.compression&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">compressed&nbsp;or&nbsp;uncompressed</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">header.size&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">文件大小</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">header.nbits&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">twips为单位的画面尺寸</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">header.xmax<br />
header.ymax<br />
header.width<br />
header.height<br />
header.version&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">flash版本</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">header.frame_date&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">帧率</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">header.frame_count&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">总帧数</span><span style="color: #008000;"><br />
</span><span style="color: #000000;"><br />
header.inspect&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">信息描述字符串</span><span style="color: #008000;"><br />
</span></div>
<br />
header.inspect一个示例输出：<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;">signature:&nbsp;&nbsp;&nbsp;CWS<br />
version:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;"><br />
compression:&nbsp;compressed<br />
size:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">5737111</span><span style="color: #000000;"><br />
nbits:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">14</span><span style="color: #000000;"><br />
xmax:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">7200</span><span style="color: #000000;"><br />
ymax:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">5760</span><span style="color: #000000;"><br />
width:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">360</span><span style="color: #000000;"><br />
height:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">288</span><span style="color: #000000;"><br />
frameRate:&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">25</span><span style="color: #000000;"><br />
frameCount:&nbsp;&nbsp;</span><span style="color: #000000;">10409</span><span style="color: #000000;"><br />
<br />
</span></div>
<br />
2、解压缩swf文件，如果源文件本身没有被压缩那么将抛出异常：<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;">require&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">swfheader</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
SwfUtil::decompress_swf(</span><span style="color: #800000;">"</span><span style="color: #800000;">c:/test.swf</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">c:/test_decompressed.swf</span><span style="color: #800000;">"</span><span style="color: #000000;">)</span></div>
<br />
3、压缩swf文件,如果源文件已经被压缩将抛出异常：<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;">require&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">swfheader</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
SwfUtil::compress_swf(</span><span style="color: #800000;">"</span><span style="color: #800000;">c:/test.swf</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">c:/test_compressed.swf</span><span style="color: #800000;">"</span><span style="color: #000000;">)</span></div>
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/233785.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> 2008-10-11 23:38 <a href="http://www.blogjava.net/killme2008/archive/2008/10/11/233785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby Tip——读文件</title><link>http://www.blogjava.net/killme2008/archive/2008/10/07/232816.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 07 Oct 2008 01:38:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/10/07/232816.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/232816.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/10/07/232816.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/232816.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/232816.html</trackback:ping><description><![CDATA[&nbsp;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;">f</span><span style="color: #000000;">=</span><span style="color: #000000;">File.open(</span><span style="color: #800000;">"</span><span style="color: #800000;">test.log</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">r</span><span style="color: #800000;">"</span><span style="color: #000000;">)<br />
result</span><span style="color: #000000;">=</span><span style="color: #800000;">''</span><span style="color: #000000;"><br />
f.each_line&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">line</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;result</span><span style="color: #000000;">+=</span><span style="color: #000000;">line<br />
end<br />
puts&nbsp;result</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;">File.open(</span><span style="color: #800000;">"</span><span style="color: #800000;">test.log</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">r</span><span style="color: #800000;">"</span><span style="color: #000000;">){&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">f</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;f.collect.join}</span></div>
<br />
利用了文件打开的IO对象混入了Enumerable模块这一特点,通过map或者collect将所有文件行放入一个数组，再join即可。<br />
<br />
更正，其实更简介的方法是：<br />
IO.read("test.log")<br />
仅限于读文本文件。<br />
<br />
这个tip的由来是我在读二进制文件的时候发现IO.read出来的大小与实际结果不符合，然后去尝试上文提到的这个方法，其实仍然是错误的。读二进制文件需要指定mode为b：<br />
File.open("test.swf","rb")<br />
<br />
仅作更正。<br /><img src ="http://www.blogjava.net/killme2008/aggbug/232816.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> 2008-10-07 09:38 <a href="http://www.blogjava.net/killme2008/archive/2008/10/07/232816.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby 1.9概要（5） 异常</title><link>http://www.blogjava.net/killme2008/archive/2008/10/03/232190.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 03 Oct 2008 05:26:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/10/03/232190.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/232190.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/10/03/232190.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/232190.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/232190.html</trackback:ping><description><![CDATA[1、<strong>异常的相等性</strong>，如果两个异常的class、message和backtrace一样，那么认为这两个异常是相等的，可以通过==判断。<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;">def</span><span style="color: #000000;">&nbsp;method<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">raise</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">foobar</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
end<br />
<br />
errors&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[]<br />
</span><span style="color: #000000;">2</span><span style="color: #000000;">.times&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;Thread.new&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;method<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rescue&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;e<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;e<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end.join<br />
end<br />
puts&nbsp;errors[</span><span style="color: #000000;">-</span><span style="color: #000000;">2</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;errors[</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">]&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">=&gt;&nbsp;true&nbsp;(1.9)&nbsp;&nbsp;&nbsp;false(1.8)</span></div>
<br />
2、<strong>SystemStackError现在继承Exception类，而非原来的StandardError</strong>:<br />
1.8&nbsp; <br />
&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;">SystemStackError&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;StandardError&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;true</span></div>
1.9<br />
&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;">SystemStackError&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;StandardError&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;nil</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;SystemStackError&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;Exception&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">=&gt;&nbsp;true</span></div>
<br />
3、<strong>移除了Exception#to_str方法</strong>：<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;">begin<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">raise</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">foo</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
rescue<br />
&nbsp;&nbsp;&nbsp;$!.to_str<br />
end<br />
<br />
</span><span style="color: #008000;">#</span><span style="color: #008000;">=&gt;&nbsp;undefind&nbsp;method&nbsp;"to_str"&nbsp;for&nbsp;#&lt;RuntimeError:foo&gt;</span></div>
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/232190.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> 2008-10-03 13:26 <a href="http://www.blogjava.net/killme2008/archive/2008/10/03/232190.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby 1.9概要（4） Block和Proc</title><link>http://www.blogjava.net/killme2008/archive/2008/10/02/232089.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 02 Oct 2008 05:54:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/10/02/232089.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/232089.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/10/02/232089.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/232089.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/232089.html</trackback:ping><description><![CDATA[1、<strong>Proc加了新方法Proc#yield</strong>,这只是Proc#call的别名方法，是为了能让Proc也可以像block那样传入方法并且调用yield。<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;">a_proc&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Proc.new&nbsp;{</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;a</span><span style="color: #000000;">+</span><span style="color: #000000;">b}<br />
a_proc.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">)&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;3</span><span style="color: #008000;"><br />
</span><span style="color: #000000;"><br />
</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;test(</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">block)<br />
&nbsp;&nbsp;block.</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">)<br />
end<br />
test&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;a</span><span style="color: #000000;">+</span><span style="color: #000000;">b&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;3</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">end<br />
test&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">a_proc&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;3</span></div>
<br />
2、<strong>没有参数的block的基数</strong>（参数个数,arity）：<br />
1.8<br />
&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;">lambda</span><span style="color: #000000;">{}.arity&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">=&gt;&nbsp;-1</span></div>
1.9<br />
&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;">lambda</span><span style="color: #000000;">{}.arity&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">=&gt;&nbsp;0</span></div>
所谓arity就是方法调用无法忽略的参数个数。这跟Erlang,Prolog中的arity的概念并无二致。<br />
<br />
3、<strong>proc关键字现在是Proc.new的同义词</strong>，proc在1.8的时候跟lambda关键字是同义词，也就是proc定义的是一个lambda而非字面<br />
<br />
意义上的Proc，1.9改过来了。<br />
1.9:<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 />
proc{</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;">}.arity&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;2</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">proc{</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;">}.call(</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;nil</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">Proc.new{</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;">}.arity&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;2</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">Proc.new{</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;">}.call(</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&nbsp;nil</span></div>
<br />
1.8:<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;">proc{</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;">}.arity&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;2</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">proc{</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;">}.call(</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;ERROR:&nbsp;(eval):1:&nbsp;wrong&nbsp;number&nbsp;of&nbsp;arguments&nbsp;(1&nbsp;for&nbsp;2)</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">Proc.new{</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;">}.arity&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;2</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">Proc.new{</span><span style="color: #000000;">|</span><span style="color: #000000;">a,b</span><span style="color: #000000;">|</span><span style="color: #000000;">}.call(</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;nil</span></div>
<br />
1.8时候第二个调用出错的原因在于lambda在调用参数过多过少的时候都将报error，这是lambda跟Proc的一个区别之一。<br />
<br />
4、<strong>Proc#lambda?</strong> 用来判断某个Proc是否具有lambda语义或者block语义：<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;">lambda</span><span style="color: #000000;">{}.</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">?&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">=&gt;true</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">proc{}.</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">?&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;false</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">Proc.new{}.</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">?&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;false</span></div>
<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/232089.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> 2008-10-02 13:54 <a href="http://www.blogjava.net/killme2008/archive/2008/10/02/232089.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby 1.9概要（3）类和模块</title><link>http://www.blogjava.net/killme2008/archive/2008/10/01/231988.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 01 Oct 2008 05:52:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/10/01/231988.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/231988.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/10/01/231988.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/231988.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/231988.html</trackback:ping><description><![CDATA[三、类和模块<br />
1、Module#instance_methods, #private_instance_methods, #public_instance_methods Module这三个方法都将返回方法名<br />
<br />
的symbol组成的数组，而非过去的字符串数组。<br />
<br />
2、Module#const_defined?, #const_get 这两个方法都添加一个参数flag，用来决定是否将它的ancestor中的const包括在查<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;A;&nbsp;X&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;foo;&nbsp;end&nbsp;end<br />
module&nbsp;B<br />
&nbsp;&nbsp;include&nbsp;A<br />
&nbsp;&nbsp;const_defined?&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">X</span><span style="color: #800000;">"</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;true</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;const_defined?&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">X</span><span style="color: #800000;">"</span><span style="color: #000000;">,false&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #008000;">#</span><span style="color: #008000;">uninitialized&nbsp;constant</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;const_get&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">X</span><span style="color: #800000;">"</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;1</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;const_get&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">X</span><span style="color: #800000;">"</span><span style="color: #000000;">,false&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">uninitialized&nbsp;constant&nbsp;&nbsp;</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">end</span></div>
<br />
3、Module#class_variable_defined?方法：<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;X;&nbsp;end<br />
X.class_variable_defined?&nbsp;:@@a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;false</span><span style="color: #008000;"><br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;X;&nbsp;@@a&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;end<br />
X.class_variable_defined?&nbsp;:@@a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;true</span></div>
class_variable_{get,set}方法：<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: #0000ff;">class</span><span style="color: #000000;">&nbsp;B;&nbsp;self&nbsp;end.class_variable_set(:@@a,&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">foo</span><span style="color: #800000;">"</span><span style="color: #000000;">)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;"foo"</span></div>
<br />
4、Module#attr等价于Module#attr_reader:<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;Test<br />
&nbsp;&nbsp;attr:foo<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;initialize<br />
&nbsp;&nbsp;&nbsp;&nbsp;@foo</span><span style="color: #000000;">=</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
&nbsp;&nbsp;end<br />
end<br />
t</span><span style="color: #000000;">=</span><span style="color: #000000;">Test.new<br />
puts&nbsp;t.foo&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">=&gt;3</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">t.foo</span><span style="color: #000000;">=</span><span style="color: #000000;">4</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">undefined&nbsp;method&nbsp;"foo="</span></div>
<br />
5、接下来是一个bug fix的问题。下面这段代码是为了证明对象的singleton类继承自对象的类：<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;X;end;&nbsp;x</span><span style="color: #000000;">=</span><span style="color: #000000;">X.new;&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;x;p&nbsp;self&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;X;&nbsp;end</span></div>
<br />
在1.8上，这段代码打印nil，这是不符合Ruby的对象模型的，因此在1.9运行已经可以打印正确结果true了。<br />
如果不理解这点，参照俺过去写的《Ruby对象模型》<br />
<br />
6、新增Module#module_exec方法，与Object#instance_exec类似<br />
<br />
7、绑定未绑定的方法时进行额外的子类型检查,例如下面的代码：<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;Foo;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;foo;&nbsp;end&nbsp;end<br />
module&nbsp;Bar<br />
&nbsp;&nbsp;&nbsp;define_method(:foo,&nbsp;Foo.instance_method(:foo))<br />
end<br />
a</span><span style="color: #000000;">=</span><span style="color: #800000;">""</span><span style="color: #000000;"><br />
a.extend&nbsp;Bar<br />
a.foo</span></div>
<br />
在1.8上，这段代码只有当执行到<strong>a.foo</strong>的时候才报错：<strong>"foo":bind arguments must be an instance of Foo(TypeError)</strong><br />
因为foo是Foo的instance method，因此调用者必须是Foo或者其子类的instance。 而在1.9中，在绑定还没有绑定的方法的时候引入了额<br />
外的检查，因此上面这段代码不必等到a.foo调用就将报错：<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;Foo;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;foo;&nbsp;end&nbsp;end<br />
module&nbsp;Bar<br />
&nbsp;&nbsp;&nbsp;define_method(:foo,&nbsp;Foo.instance_method(:foo))&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">=》&nbsp;in&nbsp;"defined_method":bind&nbsp;arguments&nbsp;&nbsp;must&nbsp;be&nbsp;a&nbsp;subclass</span><span style="color: #008000;"><br />
</span><span style="color: #000000;"><br />
of&nbsp;Foo</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TypeError</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br />
end</span></div>
<br />
8、binding#eval方法，新增加的：<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;">a</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
binding.eval(</span><span style="color: #800000;">"</span><span style="color: #800000;">p&nbsp;a</span><span style="color: #800000;">"</span><span style="color: #000000;">)&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span></div>
<br />
这个貌似与1.8中的：<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;">a</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />
eval(</span><span style="color: #800000;">"</span><span style="color: #800000;">a</span><span style="color: #800000;">"</span><span style="color: #000000;">,binding)</span></div>
<br />
没有什么不同。<img src ="http://www.blogjava.net/killme2008/aggbug/231988.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> 2008-10-01 13:52 <a href="http://www.blogjava.net/killme2008/archive/2008/10/01/231988.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby 1.9概要（2）Kernel和Object</title><link>http://www.blogjava.net/killme2008/archive/2008/10/01/231987.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 01 Oct 2008 05:48:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/10/01/231987.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/231987.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/10/01/231987.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/231987.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/231987.html</trackback:ping><description><![CDATA[二、Kernel 和 Object<br />
1、引入了BasicObject对象，作为一个顶级的空白状态对象：<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;">BasicObject.instance_methods&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;[：==，：equal?,:"!",:"!=",:__send__]</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">Object.ancestors&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;[Object,&nbsp;Kernel,&nbsp;BasicObject]</span></div>
<br />
引入这个对象对于Ruby对象体系带来的影响我还不清楚。<br />
2、instance_exec方法，允许传递参数、self到一个block并执行之,也就是说为特定的instance执行block。<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;">def</span><span style="color: #000000;">&nbsp;magic(obj)<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;obj.foo(</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">block)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;instance_exec(self,&nbsp;a,&nbsp;b,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">block)<br />
&nbsp;&nbsp;&nbsp;end<br />
end<br />
o&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Struct.new(:a,:b).new(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">)<br />
magic(o)<br />
puts&nbsp;o.foo{</span><span style="color: #000000;">|</span><span style="color: #000000;">myself,x,y</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;puts&nbsp;myself.inspect;x&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;y&nbsp;}</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;">o&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Struct.new(:val).new(</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br />
o.instance_exec(</span><span style="color: #000000;">1</span><span style="color: #000000;">){</span><span style="color: #000000;">|</span><span style="color: #000000;">arg</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;val&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;arg&nbsp;}&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">2</span></div>
<br />
<br />
在Ruby 1.8中实现这个方法：<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;Object<br />
&nbsp;&nbsp;module&nbsp;InstanceExecHelper;&nbsp;end<br />
&nbsp;&nbsp;include&nbsp;InstanceExecHelper<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;instance_exec(</span><span style="color: #000000;">*</span><span style="color: #000000;">args,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">block)&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;!&gt;&nbsp;method&nbsp;redefined;&nbsp;discarding&nbsp;old&nbsp;instance_exec</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;mname&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;InstanceExecHelper.module_eval{&nbsp;define_method(mname,&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">block)&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;begin<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;send(mname,&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">args)<br />
&nbsp;&nbsp;&nbsp;&nbsp;ensure<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InstanceExecHelper.module_eval{&nbsp;undef_method(mname)&nbsp;}&nbsp;rescue&nbsp;nil<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;ret<br />
&nbsp;&nbsp;end<br />
end</span></div>
<br />
3、Kernel的require方法载入的文件将以完整路径存储在变量$"中，等价于：<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: #800000;">"</span><span style="color: #800000;">&nbsp;&lt;&lt;&nbsp;File.expand_path(loaded_file)</span></div>
<br />
通过在irb中观察$"变量即可看出差别。<br />
<br />
4、Object#tap方法，将对象传入block并返回自身，用于链式调用：<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;">"</span><span style="color: #800000;">hello</span><span style="color: #800000;">"</span><span style="color: #000000;">.tap{</span><span style="color: #000000;">|</span><span style="color: #000000;">a</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;a.reverse!}[0]&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">=&gt;&nbsp;"o"</span><span style="color: #008000;"><br />
</span><span style="color: #800000;">"</span><span style="color: #800000;">F</span><span style="color: #800000;">"</span><span style="color: #000000;">.tap{</span><span style="color: #000000;">|</span><span style="color: #000000;">x</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;x.upcase!}[0]&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">=&gt;&nbsp;"F"&nbsp;（注意到"F".upcase!返回的是nil)</span></div>
<br />
5、Kernel#instance_variable_defined?方法：<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;">a&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">foo</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
a.instance_variable_defined?&nbsp;:@a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;false</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">a.instance_variable_set(:@a,&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br />
a.instance_variable_defined?&nbsp;:@a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;true</span></div>
<br />
6、Object#=~<br />
<br />
匹配失败的时候返回nil而不是false<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;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">=~</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;nil</span></div>
<br />
7、Kernel#define_singleton_method 方法，<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;">a&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">""</span><span style="color: #000000;"><br />
a.define_singleton_method(:foo){</span><span style="color: #000000;">|</span><span style="color: #000000;">x</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;x&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">}<br />
a.send(:foo,</span><span style="color: #000000;">2</span><span style="color: #000000;">)&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
a.foo(</span><span style="color: #000000;">2</span><span style="color: #000000;">)&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
</span></div>
<br />
8、Kernel#singleton_methods, Kernel#methods,返回的是将是方法名symbol组成的数组，过去是方法名的字符串数组。<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/231987.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> 2008-10-01 13:48 <a href="http://www.blogjava.net/killme2008/archive/2008/10/01/231987.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby 1.9概要（1）新的语法和语义</title><link>http://www.blogjava.net/killme2008/archive/2008/10/01/231985.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 01 Oct 2008 05:37:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/10/01/231985.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/231985.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/10/01/231985.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/231985.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/231985.html</trackback:ping><description><![CDATA[<br />
一、新的语法和语义<br />
1、新的Hash定义语法：<br />
例如{a:2}&nbsp; 等价于 {:a=&gt;2}<br />
但是 {"a":2} 出错，并不等价于 {:"a"=&gt;2}<br />
<br />
2、试验性质的block内的局部变量<br />
在1.8，block的与外部同名的变量是同一个变量，也就是说block内的变量也可以修改外部的同名变量，这很容易形成难以查找的bug。<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: #008000;">#</span><span style="color: #008000;">&nbsp;{常规参数;局部变量}</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">d&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;"><br />
a&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">{</span><span style="color: #000000;">|</span><span style="color: #000000;">;d</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;d&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">}<br />
a.call()<br />
d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;2</span></div>
<br />
注意到，分号后的d是block局部变量。<br />
<br />
3、block的参数现在都是局部变量<br />
<br />
4、新lambda语法，试验性质：<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;">-&gt;</span><span style="color: #000000;">a,b&nbsp;{a</span><span style="color: #000000;">+</span><span style="color: #000000;">b}.call(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">)&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</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;">-&gt;</span><span style="color: #000000;">&nbsp;{&nbsp;}.call&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;nil</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;a,&nbsp;b&nbsp;&nbsp;{&nbsp;a&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;b&nbsp;}.call(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">)&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;3</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">c&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;&nbsp;</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">&nbsp;a,&nbsp;b;&nbsp;c&nbsp;&nbsp;{&nbsp;c&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;}.call(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">);&nbsp;c&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;1（注意这里，;号的c是block的局部变量，因此c=1在lambda调用前后</span><span style="color: #000000;">没有改变。）<br />
</span></div>
<br />
5、 .()的调用方式<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: #0000ff;">lambda</span><span style="color: #000000;">{</span><span style="color: #000000;">|*</span><span style="color: #000000;">d</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;d}.call(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">)</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: #0000ff;">lambda</span><span style="color: #000000;">{</span><span style="color: #000000;">|*</span><span style="color: #000000;">d</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;d}.(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">)</span></div>
<br />
.()这样的方式都将调用接受者的call方法，无论接收者是什么，例如：<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;</span><span style="color: #800000;">"</span><span style="color: #800000;">foo</span><span style="color: #800000;">"</span><span style="color: #000000;">.(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">)&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;~&gt;&nbsp;&nbsp;undefined&nbsp;method&nbsp;`call'&nbsp;for&nbsp;"foo":String&nbsp;(NoMethodError)</span></div>
<br />
显然，这个方式另一种形式上的method_missing，比如在类中应用：<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: #0000ff;">class</span><span style="color: #000000;">&nbsp;Test<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;self.call(</span><span style="color: #000000;">*</span><span style="color: #000000;">d)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d<br />
&nbsp;&nbsp;&nbsp;end<br />
end<br />
Test.(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">)&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">]</span></div>
这个特性也是试验性质<br />
<br />
6、block可以使用&amp;block做参数咯。<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: #0000ff;">class</span><span style="color: #000000;">&nbsp;Test<br />
&nbsp;&nbsp;&nbsp;define_method&nbsp;:foo&nbsp;</span><span style="color: #0000ff;">lambda</span><span style="color: #000000;">{</span><span style="color: #000000;">|&amp;</span><span style="color: #000000;">b</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;b.call(</span><span style="color: #800000;">"</span><span style="color: #800000;">hello</span><span style="color: #800000;">"</span><span style="color: #000000;">)}<br />
end<br />
t</span><span style="color: #000000;">=</span><span style="color: #000000;">Test.new<br />
t.foo&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">b</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;puts&nbsp;b&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;hello<br />
end</span></div>
<br />
7、新的block参数语义，|v| 现在等价于 |v,|<br />
还是通过例子吧：<br />
1.8：<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;">def</span><span style="color: #000000;">&nbsp;m;&nbsp;</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">;&nbsp;end<br />
m{</span><span style="color: #000000;">|</span><span style="color: #000000;">v</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;v}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;[1,&nbsp;2]</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;!&gt;&nbsp;multiple&nbsp;values&nbsp;for&nbsp;a&nbsp;block&nbsp;parameter&nbsp;(2&nbsp;for&nbsp;1)</span></div>
1.9：<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;">def</span><span style="color: #000000;">&nbsp;m;&nbsp;</span><span style="color: #0000ff;">yield</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">;&nbsp;end<br />
m{</span><span style="color: #000000;">|</span><span style="color: #000000;">v</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;v}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;1</span></div>
<br />
8、允许数组多重展开<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;">def</span><span style="color: #000000;">&nbsp;foo(</span><span style="color: #000000;">*</span><span style="color: #000000;">a)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a<br />
end<br />
foo(</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">[</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">],&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">[</span><span style="color: #000000;">5</span><span style="color: #000000;">,</span><span style="color: #000000;">6</span><span style="color: #000000;">])&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;[1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5,&nbsp;6]</span><span style="color: #008000;"><br />
</span><span style="color: #000000;"><br />
a&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">]<br />
b&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">,</span><span style="color: #000000;">6</span><span style="color: #000000;">]<br />
[</span><span style="color: #000000;">*</span><span style="color: #000000;">a,&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">b]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;[1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5,&nbsp;6]</span></div>
<br />
9、可选参数后允许再有强制参数的存在，这在过去是不允许的。例如下面的代码在1.8是错误的，而1.9却可以正常运行：<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;">def</span><span style="color: #000000;">&nbsp;foo(a,b</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">test</span><span style="color: #800000;">"</span><span style="color: #000000;">,c)<br />
&nbsp;&nbsp;puts&nbsp;c<br />
end<br />
foo(</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;wrong&nbsp;number&nbsp;of&nbsp;arguments(</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">)<br />
foo(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;"><br />
foo(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
foo(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">)&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">3</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: #0000ff;">def</span><span style="color: #000000;">&nbsp;m(a,&nbsp;b</span><span style="color: #000000;">=</span><span style="color: #000000;">nil,&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">c,&nbsp;d)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[a,b,c,d]<br />
end<br />
m(</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">error<br />
m(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">)&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;[</span><span style="color: #000000;">1</span><span style="color: #000000;">,nil,[],</span><span style="color: #000000;">2</span><span style="color: #000000;">]<br />
m(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,[],</span><span style="color: #000000;">3</span><span style="color: #000000;">]<br />
m(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">)&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,[</span><span style="color: #000000;">3</span><span style="color: #000000;">],</span><span style="color: #000000;">4</span><span style="color: #000000;">]<br />
m(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">)&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,[</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">],</span><span style="color: #000000;">5</span><span style="color: #000000;">]<br />
m(</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">,</span><span style="color: #000000;">6</span><span style="color: #000000;">]&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,[</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">],</span><span style="color: #000000;">6</span><span style="color: #000000;">] <br />
</span></div>
<br />
10、?c的语义，过去?+字符返回字符的ascii码整数，现在返回字符"c"<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;">?a&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">97</span><span style="color: #000000;">&nbsp;&nbsp;(</span><span style="color: #000000;">1.8</span><span style="color: #000000;">)<br />
?a&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">a</span><span style="color: #800000;">"</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">1.9</span><span style="color: #000000;">)</span></div>
<br />
11、[]方法的参数现在可以将数组和hash联合使用，例如下面的例子：<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;Test<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;[](</span><span style="color: #000000;">*</span><span style="color: #000000;">a)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts&nbsp;a.inspect<br />
&nbsp;&nbsp;&nbsp;end<br />
end<br />
a</span><span style="color: #000000;">=</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">]<br />
Test.new[</span><span style="color: #000000;">*</span><span style="color: #000000;">a,:a</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">2</span><span style="color: #000000;">]&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;&nbsp;SyntaxERROR:compire&nbsp;error&nbsp;(</span><span style="color: #000000;">1.8</span><span style="color: #000000;">)<br />
Test.new[</span><span style="color: #000000;">*</span><span style="color: #000000;">a,:a</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">2</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;&nbsp;[</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,{:a</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">2</span><span style="color: #000000;">}]&nbsp;(</span><span style="color: #000000;">1.9</span><span style="color: #000000;">)</span></div>
<br />
<br />
12、打印字符，打印字符和负数，<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;">1.8</span><span style="color: #000000;">：<br />
&nbsp;&nbsp;printf&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">%c</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">a</span><span style="color: #800000;">"</span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;can</span><span style="color: #800000;">'</span><span style="color: #800000;">t&nbsp;convert&nbsp;String&nbsp;into&nbsp;Integer</span><span style="color: #800000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;printf&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">%u</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;..</span><span style="color: #000000;">4294967295</span><span style="color: #000000;"><br />
<br />
</span><span style="color: #000000;">1.9</span><span style="color: #000000;">:<br />
&nbsp;&nbsp;printf&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">%c</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">a</span><span style="color: #800000;">"</span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;a<br />
&nbsp;&nbsp;printf&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">%u</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span></div>
13、defined?方法和local variable:<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 />
RUBY_VERSION&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;"1.8.5"</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">RUBY_RELEASE_DATE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;"2006-08-25"</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">a&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;0<br />
defined?&nbsp;a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;"local-variable"</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">1</span><span style="color: #000000;">.times&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">i</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;defined?&nbsp;i&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;"local-variable(in-block)"</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">end</span></div>
<br />
VS.<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 />
RUBY_VERSION&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;"1.9.0"</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">RUBY_RELEASE_DATE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;"2007-08-03"</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">a&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;0<br />
defined?&nbsp;a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;"local-variable"</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">1</span><span style="color: #000000;">.times&nbsp;do&nbsp;</span><span style="color: #000000;">|</span><span style="color: #000000;">i</span><span style="color: #000000;">|</span><span style="color: #000000;"><br />
&nbsp;&nbsp;defined?&nbsp;i&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">&nbsp;=&gt;&nbsp;"local-variable"</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">end</span></div>
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/231985.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> 2008-10-01 13:37 <a href="http://www.blogjava.net/killme2008/archive/2008/10/01/231985.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>