﻿<?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-庄周梦蝶-随笔分类-Clojure</title><link>http://www.blogjava.net/killme2008/category/45592.html</link><description>生活、程序、未来</description><language>zh-cn</language><lastBuildDate>Tue, 25 Sep 2012 05:48:36 GMT</lastBuildDate><pubDate>Tue, 25 Sep 2012 05:48:36 GMT</pubDate><ttl>60</ttl><item><title>Clojure中文专业技术社区</title><link>http://www.blogjava.net/killme2008/archive/2012/09/25/388498.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 25 Sep 2012 04:51:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/09/25/388498.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/388498.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/09/25/388498.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/388498.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/388498.html</trackback:ping><description><![CDATA[很久没写博客，一是工作忙，二是没有太多的事情可说。<br /><br />最近在公司大佬的支持下，建立了一个Clojure语言中文方面的博客和问答网站，欢迎任何对Clojure这门基于JVM之上的函数式语言感兴趣的童鞋贡献原创文章或者资料，申请帐号请看<a href="http://blog.clojure.cn/?page_id=8">这里</a>。<br /><br />博客地址： &nbsp;<a href="http://blog.clojure.cn/">http://blog.clojure.cn/</a><br />问答网站： &nbsp;<a href="http://ask.clojure.cn/" title="http://ask.clojure.cn/">http://ask.clojure.cn/</a><br /><br />欢迎转发和注册使用，谢谢。<br /><br />邮件列表仍然使用google group：<a href="https://groups.google.com/group/cn-clojure/">https://groups.google.com/group/cn-clojure/</a><img src ="http://www.blogjava.net/killme2008/aggbug/388498.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> 2012-09-25 12:51 <a href="http://www.blogjava.net/killme2008/archive/2012/09/25/388498.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ring.velocity:render velocity templates for ring in clojure</title><link>http://www.blogjava.net/killme2008/archive/2012/07/18/383354.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 17 Jul 2012 16:07:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/07/18/383354.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/383354.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/07/18/383354.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/383354.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/383354.html</trackback:ping><description><![CDATA[<h1></h1><span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Home:&nbsp;</span><a href="https://github.com/killme2008/ring.velocity" style="font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">https://github.com/killme2008/ring.velocity<br /></a><br /><p style="margin: 0px 0px 15px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">A Clojure library designed to render velocity template for ring in clojure.<br /></p><h2><a name="usage" href="https://github.com/killme2008/ring.velocity#usage" style="margin: 0px 0px 0px -30px; padding: 0px 0px 0px 30px; border: 0px; color: rgb(65, 131, 196); text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px; "></a>Usage</h2><p style="margin: 0px 0px 15px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Adds dependency in leiningen project.clj:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  [ring.velocity "0.1.0-SNAPSHOT"] </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Create a directory named&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; background-color: #f8f8f8; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">templates</code>&nbsp;in your project directory to keep all velocity templates.</p><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Create a template&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; background-color: #f8f8f8; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">templates/test.vm</code>:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  hello,$name,your age is $age. </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Use ring.velocity in your namespace:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  (use '[ring.velocity.core :only [render]]) </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Use&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; background-color: #f8f8f8; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">render</code>&nbsp;function to render template with vars:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  (render "test.vm" :name "dennis" :age 29) </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">The&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; background-color: #f8f8f8; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">test.vm</code>&nbsp;will be interpreted equals to:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  hello,dennis,your age is 29. </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Use ring.velocity in <a href="https://github.com/weavejester/compojure/">compojure</a>:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  (defroutes app-routes      <br />    (GET "/" [] (render "test.vm" :name "dennis" :age 29))   <br />    (route/not-found "Not Found")) </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Use ring.velocity in <a href="https://github.com/ring-clojure/ring">ring</a>:</p><pre style="margin-top: 15px; margin-bottom: 15px; padding: 6px 10px; border: 1px solid #cccccc; font-size: 13px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: #f8f8f8; line-height: 19px; overflow: auto; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; color: #333333; "><code style="margin: 0px; padding: 0px; border: none; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">  (use '[ring.util.response])   <br />  (response (render "test.vm" :name "dennis" :age 29)) </code></pre><p style="margin: 15px 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Custom velocity properties,just put a file named&nbsp;<code style="margin: 0px 2px; padding: 0px 5px; border: 1px solid #eaeaea; font-size: 12px; font-family: Consolas, 'Liberation Mono', Courier, monospace; white-space: nowrap; background-color: #f8f8f8; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; ">ring-velocity.properties</code>&nbsp;to your classpath or resource paths.The default velocity properties is in&nbsp;<a href="https://github.com/killme2008/ring.velocity/blob/master/src/default/velocity.properties" style="margin: 0px; padding: 0px; border: 0px; color: #4183c4; text-decoration: none; ">src/default/velocity.properties</a>.</p><h2><a name="license" href="https://github.com/killme2008/ring.velocity#license" style="margin: 0px 0px 0px -30px; padding: 0px 0px 0px 30px; border: 0px; color: rgb(65, 131, 196); text-decoration: none; display: block; cursor: pointer; position: absolute; top: 0px; left: 0px; bottom: 0px; "></a>License</h2><p style="margin: 0px 0px 15px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Copyright &#169; 2012 dennis zhuang[killme2008@gmail.com]</p><p style="margin-top: 15px; margin-right: 0px; margin-bottom: 0px !important; margin-left: 0px; padding: 0px; border: 0px; color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; ">Distributed under the Eclipse Public License, the same as Clojure.<br /><br />Home:&nbsp;<a href="https://github.com/killme2008/ring.velocity">https://github.com/killme2008/ring.velocity</a></p><img src ="http://www.blogjava.net/killme2008/aggbug/383354.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> 2012-07-18 00:07 <a href="http://www.blogjava.net/killme2008/archive/2012/07/18/383354.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure笔记：用好type hint</title><link>http://www.blogjava.net/killme2008/archive/2012/07/10/382738.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 10 Jul 2012 12:37:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/07/10/382738.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/382738.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/07/10/382738.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/382738.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/382738.html</trackback:ping><description><![CDATA[<br />
&nbsp; &nbsp; Clojure的一大优点就是跟Java语言的完美配合，Clojure和Java之间可以相互调用，Clojure可以天然地使用Java平台上的丰富资源。在Clojure里调用一个类的方法很简单，利用dot操作符：<br />
<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(.substring&nbsp;"hello"&nbsp;3)<br />
"lo"<br />
user=&gt;&nbsp;(.substring&nbsp;"hello"&nbsp;0&nbsp;3)<br />
"hel"</div>
<br />
&nbsp; &nbsp; 上面的例子是在clojure里调用String的substring方法做字符串截取。Clojure虽然是一门弱类型的语言，但是它的Lisp Reader还是能识别大多数常见的类型，比如这里hello是一个字符串就可以识别出来,3是一个整数也可以，通过这些类型信息可以找到最匹配的substring方法，在生成字节码的时候避免使用反射，而是直接调用substring方法（INVOKEVIRTUAL指令）。<br />
<br />
&nbsp; &nbsp; 但是当你在函数里调用类方法的时候，情况就变了，例如，定义substr函数：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->(defn&nbsp;substr&nbsp;[s&nbsp;begin&nbsp;end]&nbsp;(.substring&nbsp;s&nbsp;begin&nbsp;end))</div>
<br />
&nbsp; &nbsp; 我们打开*warn-on-reflection*选项，当有反射的时候告警：<br />
<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(set!&nbsp;*warn-on-reflection*&nbsp;<span style="color: #0000FF; ">true</span>)<br />
<span style="color: #0000FF; ">true</span><br />
user=&gt;&nbsp;(defn&nbsp;substr&nbsp;[s&nbsp;begin&nbsp;end]&nbsp;(.substring&nbsp;s&nbsp;begin&nbsp;end))<br />
<strong>Reflection&nbsp;warning,&nbsp;NO_SOURCE_PATH:22&nbsp;-&nbsp;call&nbsp;to&nbsp;substring&nbsp;can't&nbsp;be&nbsp;resolved.</strong><br />
#'user/substr</div>
&nbsp; &nbsp; <br />
&nbsp; &nbsp; 问题出现了，由于函数substr里没有任何关于参数s的类型信息，为了调用s的substring方法，必须使用反射来调用，clojure编译器也警告我们调用substring没办法解析，只能通过反射调用。众所周知，反射调用是个相对昂贵的操作（对比于普通的方法调用有）。这一切都是因为clojure本身是弱类型的语言，对参数或者返回值你不需要声明类型而直接使用,Clojure会自动处理类型的转换和调用。ps.在<a href="https://github.com/technomancy/leiningen">leiningen</a>里启用反射警告很简单，在project.clj里设置：<br /><br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->;;&nbsp;Emit&nbsp;warnings&nbsp;on&nbsp;all&nbsp;reflection&nbsp;calls.<br />&nbsp;&nbsp;:warn-on-reflection&nbsp;<span style="color: #0000FF; ">true</span></div>
&nbsp; &nbsp; <br />过多的反射调用会影响效率，有没有办法避免这种情况呢？有的，Clojure提供了type hint机制，允许我们帮助编译器来生成更高效的字节码。所谓type hint就是给参数或者返回值添加一个提示：hi,clojure编译器，这是xxx类型，我想调用它的yyy方法，请生成最高效的调用代码，谢谢合作：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(defn&nbsp;substr&nbsp;[<strong>^String</strong>&nbsp;s&nbsp;begin&nbsp;end]&nbsp;(.substring&nbsp;s&nbsp;begin&nbsp;end))<br />
#'user/substr</div>
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; 这次没有警告，^String就是参数s的type hint，提示clojure编译器说s的类型是字符串，那么clojure编译器会从java.lang.String类里查找<strong>名称为substring并且接收两个参数的方法</strong>，并利用invokevirtual指令直接调用此方法，避免了反射调用。除了target对象（这里的s)可以添加type hint，方法参数和返回值也可以添加type hint：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(defn&nbsp;<strong>^{:tag&nbsp;String}</strong>&nbsp;substr&nbsp;[<strong>^String</strong>&nbsp;s&nbsp;<strong>^Integer</strong>&nbsp;begin<strong>&nbsp;^Integer</strong>&nbsp;end]&nbsp;(.substring&nbsp;s&nbsp;begin&nbsp;end))<br />
#'user/substr</div>
&nbsp; &nbsp;&nbsp;<br />
&nbsp; &nbsp; 返回值添加type hint是利用tag元数据，提示substr的返回类型是String，其他函数在使用substr的时候可以利用这个类型信息来避免反射；而参数的type hint跟target object的type hint一样以^开头加上类型，例如这里begin和end都提示说是Integer类型。<br />
<br />
&nbsp; &nbsp; <strong>问题1，什么时候应该为参数添加type hint呢？我的观点是，在任何为target object添加type hint的地方，都应该相应地为参数添加type hint，除非你事先不知道参数的类型。</strong>为什么呢？因为clojure查找类方法的顺序是这样：<br />
<br />
1.从String类里查找出所有参数个数为2并且名称为substring方法<br />
2.遍历第一步里查找出来的Method，如果你有设置参数的type hint,则
<div style="display: inline-block; "></div>
查找最匹配参数类型的Method；否则，如果第一步查找出来的Method就一个，直接使用这个Method，相反就认为没有找到对应的Method。<br />
3.如果第二步没有找到Method，使用反射调用；否则根据该Method元信息生成调用字节码。<br />
<br />
&nbsp; &nbsp;因此，如果substring方法的两个参数版本刚好就一个，方法参数有没有type hint都没有关系（有了错误的type hint反而促使反射的发生），我们都会找到这个唯一的方法；但是如果目标方法的有多个重载方法并且参数相同，而只是参数类型不同（Java里是允许方法的参数类型重载的，Clojure只允许函数的参数个数重载），那么如果没有方法参数的type hint，Clojure编译器仍然无法找到合适的调用方法，而只能通过反射。<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;看一个例子,定义get-bytes方法调用String.getBytes：<br />
<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(defn&nbsp;get-bytes&nbsp;[s&nbsp;charset]&nbsp;(.getBytes&nbsp;s&nbsp;charset))<br />
<strong>Reflection&nbsp;warning,&nbsp;NO_SOURCE_PATH:26&nbsp;-&nbsp;call&nbsp;to&nbsp;getBytes&nbsp;can't&nbsp;be&nbsp;resolved</strong>.<br />
#'user/get-bytes<br />
user=&gt;&nbsp;(defn&nbsp;get-bytes&nbsp;[<strong>^String</strong>&nbsp;s&nbsp;charset]&nbsp;(.getBytes&nbsp;s&nbsp;charset))<br />
<strong>Reflection&nbsp;warning,&nbsp;NO_SOURCE_PATH:27&nbsp;-&nbsp;call&nbsp;to&nbsp;getBytes&nbsp;can't&nbsp;be&nbsp;resolved.</strong><br />
#'user/get-bytes</div>
<br />
&nbsp; &nbsp; 第一次定义，s和charset都没有设置type hint，有反射警告；第二次，s设置了type hint，但是还是有反射警告。原因就在于String.getBytes有两个重载方法，参数个数都是一个，但是接收不同的参数类型，一个是String的charset名称，一个Charset对象。如果我们明确地知道这里charset是字符串，那么还可以为charset添加type hint:<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(defn&nbsp;get-bytes&nbsp;[<strong>^String</strong>&nbsp;s&nbsp;<strong>^String</strong>&nbsp;charset]&nbsp;(.getBytes&nbsp;s&nbsp;charset))<br />
#'user/get-bytes</div>
&nbsp; &nbsp;<br />
&nbsp; &nbsp; 这次才真正的没有警告了。总结：在设置type hint的时候，不要只考虑被调用的target object，也要考虑调用的方法参数。<br />
<br />
&nbsp; &nbsp; 问题2：什么时候应该添加tag元数据呢？理论上，在任何你明确知道返回类型的地方都应该添加tag，但是这不是教条，如果一个偶尔被调用的方法是无需这样做的。这一点只对写库的童鞋要特别注意。<br />
<br />
&nbsp; &nbsp; Type hint的原理在上文已经大概描述了下，具体到clojure源码级别，请参考clojure.lang.Compiler.InstanceMethodExpr类的构造函数和emit方法。最后，附送是否使用type hint生成substr函数的字节码之间的差异对比：<br />
<table border="1" cellspacing="2" cellpadding="2" width="500">
     <tbody>
         <tr>
             <td>未使用type hint</td>
             <td>使用type hint</td>
         </tr>
         <tr>
             <td>
             <p>&nbsp; // access flags 1</p>
             <p>&nbsp; public invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;</p>
             <p>&nbsp;&nbsp; L0</p>
             <p>&nbsp; &nbsp; LINENUMBER 14 L0</p>
             <p>&nbsp;&nbsp; L1</p>
             <p>&nbsp; &nbsp; LINENUMBER 14 L1</p>
             <p>&nbsp; &nbsp; ALOAD 1</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 1</p>
             <p>&nbsp; &nbsp; LDC "substring"</p>
             <p>&nbsp; &nbsp; ICONST_2</p>
             <p>&nbsp; &nbsp; ANEWARRAY java/lang/Object</p>
             <p>&nbsp; &nbsp; DUP</p>
             <p>&nbsp; &nbsp; ICONST_0</p>
             <p>&nbsp; &nbsp; ALOAD 2</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 2</p>
             <p>&nbsp; &nbsp; AASTORE</p>
             <p>&nbsp; &nbsp; DUP</p>
             <p>&nbsp; &nbsp; ICONST_1</p>
             <p>&nbsp; &nbsp; ALOAD 3</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 3</p>
             <p>&nbsp; &nbsp; AASTORE</p>
             <p>&nbsp; &nbsp; <strong>INVOKESTATIC clojure/lang/Reflector.invokeInstanceMethod (Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;</strong></p>
             <p>&nbsp;&nbsp; L2</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE this Ljava/lang/Object; L0 L2 0</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE s Ljava/lang/Object; L0 L2 1</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE begin Ljava/lang/Object; L0 L2 2</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE end Ljava/lang/Object; L0 L2 3</p>
             <p>&nbsp; &nbsp; ARETURN</p>
             <p>&nbsp; &nbsp; MAXSTACK = 0</p>
             <p>&nbsp; &nbsp; MAXLOCALS = 0</p>
             </td>
             <td>
             <p>public invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;</p>
             <p>&nbsp;&nbsp; L0</p>
             <p>&nbsp; &nbsp; LINENUMBER 15 L0</p>
             <p>&nbsp;&nbsp; L1</p>
             <p>&nbsp; &nbsp; LINENUMBER 15 L1</p>
             <p>&nbsp; &nbsp; ALOAD 1</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 1</p>
             <p>&nbsp; &nbsp; CHECKCAST java/lang/String</p>
             <p>&nbsp; &nbsp; ALOAD 2</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 2</p>
             <p>&nbsp; &nbsp; CHECKCAST java/lang/Number</p>
             <p>&nbsp; &nbsp; INVOKESTATIC clojure/lang/RT.intCast (Ljava/lang/Object;)I</p>
             <p>&nbsp; &nbsp; ALOAD 3</p>
             <p>&nbsp; &nbsp; ACONST_NULL</p>
             <p>&nbsp; &nbsp; ASTORE 3</p>
             <p>&nbsp; &nbsp; CHECKCAST java/lang/Number</p>
             <p>&nbsp; &nbsp; INVOKESTATIC clojure/lang/RT.intCast (Ljava/lang/Object;)I</p>
             <p>&nbsp; &nbsp; <strong>INVOKEVIRTUAL java/lang/String.substring (II)Ljava/lang/String;</strong></p>
             <p>&nbsp;&nbsp; L2</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE this Ljava/lang/Object; L0 L2 0</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE s Ljava/lang/Object; L0 L2 1</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE begin Ljava/lang/Object; L0 L2 2</p>
             <p>&nbsp; &nbsp; LOCALVARIABLE end Ljava/lang/Object; L0 L2 3</p>
             <p>&nbsp; &nbsp; ARETURN</p>
             <p>&nbsp; &nbsp; MAXSTACK = 0</p>
             <p>&nbsp; &nbsp; MAXLOCALS = 0</p>
             </td>
         </tr>
     </tbody>
</table>
<br />
&nbsp; &nbsp;&nbsp;<br />
&nbsp; &nbsp; 对比很明显，没有使用type hint，调用clojure.lang.Reflector的invokeInstanceMethod方法，使用反射调用（具体见clojure.lang.Reflector.java)，而使用了type hint之后，则直接使用invokevirtual指令（其他方法可能是invokestatic或者invokeinterface等指令）调用该方法，避免了反射。<br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp; &nbsp; 参考：<br />
<ul>
<li><a href="http://clojure.org/java_interop#Java%20Interop-Type%20Hints">Type hint官方指南</a></li>
<li><a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10.1.4.5.invokevirtual">invokevirtual指令</a></li>
<li><a href="https://github.com/clojure/clojure">Clojure源码</a></li>
</ul><img src ="http://www.blogjava.net/killme2008/aggbug/382738.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> 2012-07-10 20:37 <a href="http://www.blogjava.net/killme2008/archive/2012/07/10/382738.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：利用HouseMD诊断clojure</title><link>http://www.blogjava.net/killme2008/archive/2012/06/15/380822.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 14 Jun 2012 18:52:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/06/15/380822.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/380822.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/06/15/380822.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/380822.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/380822.html</trackback:ping><description><![CDATA[<br />
&nbsp; &nbsp; <a href="https://github.com/zhongl/HouseMD">HouseMD</a>是淘宝的聚石写的一个非常优秀的Java进程运行时诊断和调试工具，如果你接触过btrace，那么HouseMD也许你应该尝试下，它比btrace更易用，不需要写脚本，类似strace的方式attach到jvm进程做跟踪调试。<br />
<br />
&nbsp; &nbsp; 基本的安装和使用请看这篇文档《<a href="https://github.com/zhongl/HouseMD/wiki/UserGuideCN">UserGuide</a>》，恕不重复。以下内容都假设你正确安装了housemd。<br />
<br />
&nbsp; &nbsp; 本文主要介绍下怎么用housemd诊断跟踪clojure进程。Clojure的java实现也是跑在JVM里，当然也可以用housemd。<br /><br />
&nbsp; &nbsp; 我们以一个简单的例子开始，假设我们有如下clojure代码：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->(loop&nbsp;[x&nbsp;1]<br />
&nbsp;&nbsp;(Thread/sleep&nbsp;1000)<br />
&nbsp;&nbsp;(prn&nbsp;x)<br />
&nbsp;&nbsp;(recur (inc x)))</div>
<br />
&nbsp; &nbsp; 这段很简单，只是间隔一秒不断地打印递增的数字x。我们准备用housemd跟踪这个程序的运行，首先运行这个程序，你可以用lein，也可以直接java命令运行：<br />
<div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
-->java&nbsp;-cp&nbsp;clojure.jar&nbsp;clojure.main&nbsp;test.clj</div>
<br />
&nbsp; &nbsp; 运行时不断地在控制台打印数字，通过jps或者ps查询到该进程的id，假设为pid，使用housemd连接到该进程：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
-->housemd&nbsp;&lt;pid&gt;</div>
&nbsp; &nbsp; 顺利进入housemd的交互控制台，通过help命令可以查询支持的命令：<br />
<br />
<div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->housemd&gt;&nbsp;help<br />
<br />
quit&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;terminate&nbsp;the&nbsp;process.<br />
help&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display&nbsp;<span style="color: #0000FF; ">this</span>&nbsp;infomation.<br />
trace&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display&nbsp;or&nbsp;output&nbsp;infomation&nbsp;of&nbsp;method&nbsp;invocaton.<br />
loaded&nbsp;&nbsp;&nbsp;&nbsp;display&nbsp;loaded&nbsp;classes&nbsp;information.</div>
<br />
&nbsp; &nbsp; 要用housemd调试clojure，你需要对clojure的实现有一点点了解，有兴趣可以看过去的一篇blog《<a href="http://www.blogjava.net/killme2008/archive/2010/07/11/325775.html">clojure hacking guide</a>》，简单来说，clojure的编译器会将clojure代码编译成java类并运行。对于JVM来说，clojure生成的类，跟java编译器生成类没有什么不同。<br />
&nbsp; &nbsp; 具体到上面的clojure代码，会生成一个名为<strong>user$eval1</strong>的类，user是默认的namespace，而eval1是clojure编译器自动生成的一个标示类名，通过<strong>loaded</strong>命令查询类的加载情况：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->housemd&gt;&nbsp;loaded&nbsp;user$eval1&nbsp;-h<br />
user$eval1&nbsp;-&gt;&nbsp;<span style="color: #0000FF; ">null</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;clojure.lang.DynamicClassLoader@1d25d06e<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;clojure.lang.DynamicClassLoader@1d96f4b5<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;sun.misc.Launcher$ExtClassLoader@69cd2e5f</div>
<br />
&nbsp; &nbsp; 通过-h选项打印了加载user$eval1的类加载器的层次关系，因为user$eval1是动态生成的（clojure启动过程中），因此它不在任何一个class或者jar文件中。除了查询user namespace的类之外，你还可以查询clojure.core,clojure.lang,clojure.java等任何被加载进来的类，例如查询clojure.core.prn的类,在clojure里这是一个函数，在jvm看来这只是一个类：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->housemd&gt;&nbsp;loaded&nbsp;-h&nbsp;core$prn<br />clojure.core$prn&nbsp;-&gt;&nbsp;/Volumes/HDD/Users/apple/clojure/clojure.jar<br />&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;sun.misc.Launcher$ExtClassLoader@69cd2e5f</div>&nbsp; &nbsp;注意，不需要完整的namespace&#8212;&#8212;clojure.core，直接core$prn即可。其他也是类似。<strong>小技巧：如果你实在不知道clojure编译器生成的类名，你可以利用jvm自带的jmap命令来查询。</strong><br /><br />&nbsp; &nbsp;接下来，我们尝试用trace命令跟踪方法的运行，例如例子中的clojure代码用到了loop和recur两个sepcial form，我们跟踪下loop:<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->housemd&gt;&nbsp;trace&nbsp;-t&nbsp;5&nbsp;core$loop<br />INFO&nbsp;:&nbsp;probe&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;clojure.core$loop<br />core$loop.doInvoke(Object,&nbsp;Object,&nbsp;Object,&nbsp;Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br />core$loop.getRequiredArity()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br /><br />core$loop.doInvoke(Object,&nbsp;Object,&nbsp;Object,&nbsp;Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br />core$loop.getRequiredArity()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br /><br />core$loop.doInvoke(Object,&nbsp;Object,&nbsp;Object,&nbsp;Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br />core$loop.getRequiredArity()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br /><br />core$loop.doInvoke(Object,&nbsp;Object,&nbsp;Object,&nbsp;Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br />core$loop.getRequiredArity()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br /><br />core$loop.doInvoke(Object,&nbsp;Object,&nbsp;Object,&nbsp;Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br />core$loop.getRequiredArity()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-ms&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">null</span><br /><br />INFO&nbsp;:&nbsp;Ended&nbsp;by&nbsp;timeout<br />INFO&nbsp;:&nbsp;reset&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;clojure.core$loop</div><br />&nbsp; &nbsp; 在5秒内，clojure.core$loop类有两个方法各被调用了5次，doInvoke是实际的调用，而getRequiredArity用来查询loop所需要的参数个数。trace还可以跟踪到具体的方法，例如我们跟踪prn函数的调用情况：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->housemd&gt;&nbsp;trace&nbsp;-t&nbsp;5&nbsp;core$prn.<strong>doInvoke</strong><br />INFO&nbsp;:&nbsp;probe&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;clojure.core$prn<br />core$prn.doInvoke(Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1ms&nbsp;&nbsp;&nbsp;&nbsp;clojure.core$prn@3e4ac866<br /><br />core$prn.doInvoke(Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;1ms&nbsp;&nbsp;&nbsp;&nbsp;clojure.core$prn@3e4ac866<br /><br />core$prn.doInvoke(Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;1ms&nbsp;&nbsp;&nbsp;&nbsp;clojure.core$prn@3e4ac866<br /><br />core$prn.doInvoke(Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;1ms&nbsp;&nbsp;&nbsp;&nbsp;clojure.core$prn@3e4ac866<br /><br />core$prn.doInvoke(Object)&nbsp;&nbsp;&nbsp;&nbsp;sun.misc.Launcher$AppClassLoader@a6eb38a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;1ms&nbsp;&nbsp;&nbsp;&nbsp;clojure.core$prn@3e4ac866<br /><br />INFO&nbsp;:&nbsp;Ended&nbsp;by&nbsp;timeout<br />INFO&nbsp;:&nbsp;reset&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;clojure.core$prn</div>&nbsp;&nbsp;<br />&nbsp; &nbsp;trace打印了方法的调用次数（5秒内）和每次调用的时间（毫秒级别），以及调用的target object<strong>。小技巧：没有可变参数的函数生成类最终调用的是invoke方法（参数个数可能重载），有可变参数的函数调用的是doInvoke方法。<br /><br /></strong>&nbsp; &nbsp;trace命令还支持打印调用堆栈到文件，例如：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->trace&nbsp;-t&nbsp;5&nbsp;-d&nbsp;-s&nbsp;&nbsp;core$prn.doInvoke</div><br />&nbsp; &nbsp;利用-s和-d命令会将详细的调用信息输出到临时目录，临时目录的路径可以通过trace help命令查询到，在我的机器上是/tmp/trace/&lt;pid&gt;@host目录下。调用堆栈的输出类似：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->example$square.invoke(Long)&nbsp;call&nbsp;by&nbsp;thread&nbsp;[main]<br />&nbsp;&nbsp;&nbsp;&nbsp;example$eval9.invoke(test.clj:11)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.Compiler.eval(Compiler.java:6465)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.Compiler.load(Compiler.java:6902)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.Compiler.loadFile(Compiler.java:6863)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.main$load_script.invoke(main.clj:282)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.main$script_opt.invoke(main.clj:342)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.main$main.doInvoke(main.clj:426)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.RestFn.invoke(RestFn.java:421)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.Var.invoke(Var.java:405)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.AFn.applyToHelper(AFn.java:163)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.lang.Var.applyTo(Var.java:518)<br />&nbsp;&nbsp;&nbsp;&nbsp;clojure.main.main(main.java:37)</div><br />&nbsp; &nbsp;上面这个简单的例子展示了使用housemd跟踪诊断clojure进程的方法。<br /><br />&nbsp; &nbsp;自定义ns和函数的调试与此类似，假设我们有下面的clojure代码：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(ns&nbsp;example)<br />(defn&nbsp;square&nbsp;[x]<br />&nbsp;&nbsp;(*&nbsp;x&nbsp;x))<br /><br />(loop&nbsp;[x&nbsp;1]<br />&nbsp;&nbsp;(Thread/sleep&nbsp;1000)<br />&nbsp;&nbsp;(square&nbsp;x)<br />&nbsp;&nbsp;(recur&nbsp;(inc&nbsp;x)))</div>&nbsp;<br />&nbsp; &nbsp;ns为example，自定义函数square并定期循环调用。使用housemd诊断这段代码：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->loaded&nbsp;-h&nbsp;example$square&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#查询square的加载情况<br />trace&nbsp;-t&nbsp;10 -d -s example$square.invoke&nbsp;&nbsp;#跟踪10秒内square的调用情况</div><img src ="http://www.blogjava.net/killme2008/aggbug/380822.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> 2012-06-15 02:52 <a href="http://www.blogjava.net/killme2008/archive/2012/06/15/380822.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Emacs + Clojure配置的几个Tip</title><link>http://www.blogjava.net/killme2008/archive/2012/05/19/378535.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 18 May 2012 16:57:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/05/19/378535.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/378535.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/05/19/378535.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/378535.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/378535.html</trackback:ping><description><![CDATA[<br />
&nbsp; &nbsp; 很久没更新博客了，在北京工作，忙碌并且充实。目前来说，Clojure最好的开发编辑器应该是Emacs + <a href="http://common-lisp.net/project/slime/doc/html/">Slime</a>的组合，利用<a href="https://github.com/technomancy/swank-clojure">swank-clojure</a>这个项目，加上clojure-mode，可以完美地运行slime。编译、运行、跳转、文档和引用查看甚至<a href="http://georgejahad.com/clojure/swank-cdt.html">debug</a>都可以搞定。具体配置恕不重复，看swank-clojure的文档即可自己安装起来，或者这篇<a href="http://sunng.info/blog/2011/09/beginning-emacs-for-clojure/">中文博客</a>，<a href="http://www.cnblogs.com/darkluck99/archive/2012/02/20/2360216.html">windows上配置</a>。<br />
<br />
&nbsp; &nbsp; 分享几个Tip，也期待大家分享你们的使用心得。<br />
<br />
&nbsp; &nbsp; 首先是自动在打开clj后缀文件的时候启动执行clojure-jack-in与slime连接，可以在emacs配置里加上个callback：<br />
<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(eval-after-load&nbsp;"clojure-mode"<br />&nbsp;&nbsp;'(progn<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(require&nbsp;'slime)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(require&nbsp;'clojure-mode)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(unless&nbsp;(slime-connected-p)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(save-excursion&nbsp;(clojure-jack-in)))))</div>
&nbsp; &nbsp; 这样在打开clj为后缀的文件的时候，将自动启动clojure-mode执行clojure-jack-in函数并且连接slime。<br /><br />&nbsp; &nbsp; 将clj后缀的文件自动关联到clojure-mode:<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->(setq&nbsp;auto-mode-alist&nbsp;(cons&nbsp;'("\\.clj$"&nbsp;.&nbsp;clojure-mode)&nbsp;auto-mode-alist))</div>
&nbsp; &nbsp; 通常来说如果你是利用<a href="http://marmalade-repo.org/">marmalade</a>安装的，会自动关联的。<br /><br />&nbsp; &nbsp; 另外，启动自动匹配括号、字符串引号等的paredit模式一定要启动：<br /><div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(defun&nbsp;paredit-mode-enable&nbsp;()&nbsp;(paredit-mode&nbsp;1))<br />(add-hook&nbsp;'clojure-mode-hook&nbsp;'paredit-mode-enable)<br />(add-hook&nbsp;'clojure-test-mode-hook&nbsp;'paredit-mode-enable)</div><br />
&nbsp; &nbsp;在使用clojure-mode或者clojure-test-mode的时候自动启用paredit模式，括号再也不是问题。括号匹配提示一般是开启的，如果没有，强制开启：<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->;;&nbsp;&nbsp;&nbsp;&nbsp;显示括号匹配<br />(show-paren-mode&nbsp;t)<br />(setq&nbsp;show-paren-style&nbsp;'parentheses)</div><br />&nbsp; &nbsp; slime更多配置，启用IO重定向（多线程IO输出都定向到SLIME repl）以及设置通讯字符编码等：<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(eval-after-load&nbsp;"slime"<br />&nbsp;&nbsp;'(progn<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(slime-setup&nbsp;'(slime-repl&nbsp;slime-fuzzy))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;(setq&nbsp;slime-truncate-lines&nbsp;t)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(setq&nbsp;&nbsp;swank:*globally-redirect-io*&nbsp;&nbsp;t)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;(setq&nbsp;slime-complete-symbol-function&nbsp;'&nbsp;slime-fuzzy-complete-symbol)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(setq&nbsp;slime-net-coding-system&nbsp;'utf-8-unix)))</div><br />&nbsp; &nbsp; 细心的朋友可能注意到我注释了slime-fuzzy-complete的配置，这是一个支持更好的自动补全功能的SLIME插件（可以用缩写来自动补全），可惜在我机器上没有尝试配置成功，有兴趣你可以尝试下。<br /><br />&nbsp; &nbsp; 在REPL里支持语法高亮，一定要配置上：<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(add-hook&nbsp;'slime-repl-mode-hook<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(defun&nbsp;clojure-mode-slime-font-lock&nbsp;()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(require&nbsp;'clojure-mode)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;(font-lock-mode)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(clojure-mode-font-lock-setup))))</div><br />&nbsp; &nbsp; 单独在clojure-mode（在其他mode里这些快捷键不会起作用）里配置快捷键可以这样:<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(eval-after-load&nbsp;"clojure-mode"<br />&nbsp;&nbsp;'(progn<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(require&nbsp;'slime)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(require&nbsp;'clojure-mode)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(define-key&nbsp;clojure-mode-map&nbsp;(kbd&nbsp;"M-/")&nbsp;&nbsp;(quote&nbsp;slime-complete-symbol))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(define-key&nbsp;clojure-mode-map&nbsp;(kbd&nbsp;"C-c&nbsp;s")&nbsp;&nbsp;(quote&nbsp;slime-selector)))</div><br />&nbsp; &nbsp;例如我这里将M-/作为自动补全的快捷键，因为meta键在我的Mac机器上设置为command键，因此自动补全的操作习惯就跟Eclipse类似。而<strong>slime-selector</strong>是一个非常有用的函数，用来跳转到slime的一系列buffer，因此我绑定了C-c s快捷键。<br /><br />&nbsp; &nbsp; 额外一提，在Mac osx下，将command作为meta键:<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all">;;;&nbsp;I&nbsp;prefer&nbsp;cmd&nbsp;key&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;meta<br />(setq&nbsp;mac-option-key-is-meta&nbsp;nil<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mac-command-key-is-meta&nbsp;t<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mac-command-modifier&nbsp;'meta<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mac-option-modifier&nbsp;'none)</div><br />&nbsp; &nbsp; 最后，期待大家不吝分享你的心得。<br />&nbsp; &nbsp;&nbsp;<img src ="http://www.blogjava.net/killme2008/aggbug/378535.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> 2012-05-19 00:57 <a href="http://www.blogjava.net/killme2008/archive/2012/05/19/378535.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>clj.monitor : monitoring applications in clojure based on SSH</title><link>http://www.blogjava.net/killme2008/archive/2012/05/12/378018.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 12 May 2012 14:38:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/05/12/378018.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/378018.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/05/12/378018.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/378018.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/378018.html</trackback:ping><description><![CDATA[<div><br />&nbsp; &nbsp; My weekend project clj.monitor is beta release,it's a clojure DSL for monitoring system and applications based on SSH.<br />
<br />
Home:<a href="https://github.com/killme2008/clj.monitor">https://github.com/killme2008/clj.monitor
<br /></a><br />
An example:<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->(ns&nbsp;clj.monitor.example<br />
&nbsp;&nbsp;(:use&nbsp;[clj.monitor.core]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[control.core]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[clj.monitor.tasks]))<br />
<br />
;;define&nbsp;a&nbsp;mysql&nbsp;cluster<br />
(defcluster&nbsp;mysql<br />
&nbsp;&nbsp;:clients&nbsp;[{:user&nbsp;"deploy"&nbsp;:host&nbsp;"mysql.app.com"}])<br />
<br />
;;define&nbsp;a&nbsp;monitor&nbsp;for&nbsp;mysql&nbsp;cluster<br />
(defmonitor&nbsp;mysql-monitor<br />
&nbsp;&nbsp;:tasks&nbsp;[(ping-mysql&nbsp;"root"&nbsp;"password")<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (system-load&nbsp;:5&nbsp;3)]<br />
&nbsp;&nbsp;:clusters&nbsp;[:mysql])<br />
<br />
;;start&nbsp;monitors<br />
(start-monitors<br />
&nbsp;:cron&nbsp;"*&nbsp;0/5&nbsp;*&nbsp;*&nbsp;*&nbsp;?"<br />
&nbsp;:alerts&nbsp;[(mail&nbsp;:from&nbsp;"alert@app.com"&nbsp;:to&nbsp;"yourname@app.com")]<br />
&nbsp;:monitors&nbsp;[mysql-monitor])</div>
<br />
API document:<a href="http://fnil.net/clj.monitor">&nbsp;http://fnil.net/clj.monitor
</a>
<br />
<br />It is just a beta release,if you have any questions or find issues ,please let me know,thanks.
</div><img src ="http://www.blogjava.net/killme2008/aggbug/378018.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> 2012-05-12 22:38 <a href="http://www.blogjava.net/killme2008/archive/2012/05/12/378018.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：静态代码分析</title><link>http://www.blogjava.net/killme2008/archive/2012/03/23/372576.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 23 Mar 2012 13:28:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/03/23/372576.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/372576.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/03/23/372576.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/372576.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/372576.html</trackback:ping><description><![CDATA[&nbsp; &nbsp; Java世界里有<a href="http://findbugs.sourceforge.net/">findbugs</a>这样的神器，可以让你避免很多&#8220;简单愚蠢&#8221;的bug。同样，Clojure世界里也有相应的替代品，这就是今天要介绍的<a href="https://github.com/jonase/kibit">kibit</a>。不过kibit现在还比较年轻，判断的规则较少，但是已经可以使用起来做clojure代码的静态检查。<br />
<br />
项目主页：<a href="https://github.com/jonase/kibit">https://github.com/jonase/kibit
</a>
<br />
使用：<br />
1.安装lein插件：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->lein&nbsp;plugin&nbsp;install&nbsp;jonase/kibit&nbsp;0.0.2</div>
<br />
2.在项目的根目录运行<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->lein&nbsp;kibit</div>
<br />
kibit会分析项目里所有clojure源码，每个namespace分别分析，例如我分析<a href="http://github.com/killme2008/clojure-control">clojure-control</a>的输出：<br />
<br />
<div style="font-size: 13px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; border-image: initial; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->==&nbsp;control.commands&nbsp;==<br />
==&nbsp;control.core&nbsp;==<br />
[186]&nbsp;Consider&nbsp;(zero?&nbsp;(:status&nbsp;(ssh&nbsp;host&nbsp;user&nbsp;cluster&nbsp;(str&nbsp;"test&nbsp;-e&nbsp;"&nbsp;file))))&nbsp;instead&nbsp;of&nbsp;(=&nbsp;(:status&nbsp;(ssh&nbsp;host&nbsp;user&nbsp;cluster&nbsp;(str&nbsp;"test&nbsp;-e&nbsp;"&nbsp;file)))&nbsp;0)<br />
==&nbsp;control.main&nbsp;==<br />
==&nbsp;leiningen.control&nbsp;==<br />
[<span style="color: #0000FF; ">null</span>]&nbsp;Consider&nbsp;Integer/parseInt&nbsp;instead&nbsp;of&nbsp;(fn*&nbsp;[p1__61444#]&nbsp;(Integer/parseInt&nbsp;p1__61444#))<br />
[<span style="color: #0000FF; ">null</span>]&nbsp;Consider&nbsp;Integer/parseInt&nbsp;instead&nbsp;of&nbsp;(fn*&nbsp;[p1__65254#]&nbsp;(Integer/parseInt&nbsp;p1__65254#))</div>
<br />&nbsp; &nbsp; 显然，kibit一个一个namespace分析过去，并且按照规则对它认为有问题的地方打印出来，并提出建议。例如这里它建议我用<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(zero?&nbsp;(:status&nbsp;(ssh&nbsp;host&nbsp;user&nbsp;cluster&nbsp;(str&nbsp;"test&nbsp;-e&nbsp;"&nbsp;file))))</div>
&nbsp; &nbsp; 替换control.core里186行的：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->&nbsp;(=&nbsp;(:status&nbsp;(ssh&nbsp;host&nbsp;user&nbsp;cluster&nbsp;(str&nbsp;"test&nbsp;-e&nbsp;"&nbsp;file)))&nbsp;0)</div><br />&nbsp; &nbsp; 目前kibit大多数是这类代码风格上的检查，还没有做到类似findbugs那样更丰富的检查，例如NPE异常检查等。此外kibit还提供反射检查，任何有反射调用的地方都给出警告。<br />&nbsp; &nbsp; kibit是基于<a href="https://github.com/clojure/core.logic">core.logic</a>实现的，它的规则都放在了<a href="https://github.com/jonase/kibit/tree/master/src/jonase/kibit/rules">这里</a>，通过defrules宏来定义检查规则，源码中对算术运算的规则定义：<br /><div style="font-size: 13px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; border-image: initial; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->(defrules&nbsp;rules<br />&nbsp;&nbsp;[(+&nbsp;?x&nbsp;1)&nbsp;(inc&nbsp;?x)]<br />&nbsp;&nbsp;[(+&nbsp;1&nbsp;?x)&nbsp;(inc&nbsp;?x)]<br />&nbsp;&nbsp;[(-&nbsp;?x&nbsp;1)&nbsp;(dec&nbsp;?x)]<br /><br />&nbsp;&nbsp;[(*&nbsp;?x&nbsp;(*&nbsp;.&nbsp;?xs))&nbsp;(*&nbsp;?x&nbsp;.&nbsp;?xs)]<br />&nbsp;&nbsp;[(+&nbsp;?x&nbsp;(+&nbsp;.&nbsp;?xs))&nbsp;(+&nbsp;?x&nbsp;.&nbsp;?xs)])</div>&nbsp; &nbsp;<br />&nbsp; &nbsp; 第一个规则，任何对类似(+ 1 x)的代码，都建议替换成(inc x)，后面的与此类似。理论上你也可以自定义规则，并提交给官方。总体上说kibit仍然是比不上findbugs的，期待未来发展的更好。<img src ="http://www.blogjava.net/killme2008/aggbug/372576.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> 2012-03-23 21:28 <a href="http://www.blogjava.net/killme2008/archive/2012/03/23/372576.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：如何做性能测试</title><link>http://www.blogjava.net/killme2008/archive/2012/03/22/372489.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 22 Mar 2012 13:14:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/03/22/372489.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/372489.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/03/22/372489.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/372489.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/372489.html</trackback:ping><description><![CDATA[<br />
&nbsp; &nbsp; 我们经常需要在程序中测量某段代码的性能，或者某个函数的性能，在Java中，我们可能简单地循环调用某个方法多少次，然后利用System.currentTimeMillis()方法测量下时间。在Ruby中，一般都是用<a href="http://www.ruby-doc.org/stdlib-1.9.3/libdoc/benchmark/rdoc/index.html">Benchmark module</a>做测试，提供了更详细的报告信息。<br />
<br />
&nbsp; &nbsp; 同样，在Clojure里你可以做这些事情，你仍然可以使用System.currentTimeMillis()来测量运行时间，例如：<br />
<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(defn&nbsp;sum1&nbsp;[&amp;&nbsp;args]&nbsp;(reduce&nbsp;+&nbsp;0&nbsp;args))<br />
#'user/sum1<br />
<br />
user=&gt;&nbsp;(defn&nbsp;sum2&nbsp;[&amp;&nbsp;args]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(loop&nbsp;[rt&nbsp;0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;args&nbsp;args]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<span style="color: #0000FF; ">if</span>&nbsp;args<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(recur&nbsp;(+&nbsp;rt&nbsp;(first&nbsp;args))&nbsp;(next&nbsp;args))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rt)))<br />
#'user/sum2<br />
<br />
user=&gt;&nbsp;(defn&nbsp;bench&nbsp;[sum&nbsp;n]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[start&nbsp;(System/currentTimeMillis)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nums&nbsp;(range&nbsp;0&nbsp;(+&nbsp;n&nbsp;1))]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(dotimes&nbsp;[_&nbsp;n]&nbsp;(apply&nbsp;sum&nbsp;nums))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(println&nbsp;(-&nbsp;(System/currentTimeMillis)&nbsp;start))))<br />
<br />
user=&gt;&nbsp;(bench&nbsp;sum1&nbsp;10000)<br />
1818<br />
nil<br />
user=&gt;&nbsp;(bench&nbsp;sum2&nbsp;10000)<br />
4220<br />
nil</div>
&nbsp; &nbsp;<br />
&nbsp; &nbsp; 定义两个求和函数sum1和sum2，一个是利用reduce，一个是自己写loop，然后写了个bench函数循环一定次数执行sum函数并给出执行时间，利用System.currentTimeMillis()方法。显然sum1比sum2快了一倍多。为什么更快？这不是我们的话题，有兴趣可以自己看reduce函数的实现。<br />
<br />
&nbsp; &nbsp; 除了用System.currentTimeMillis()这样的java方式测量运行时间外，clojure还提供了time宏来包装这一切：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(doc&nbsp;time)<br />
-------------------------<br />
clojure.core/time<br />
([expr])<br />
Macro<br />
&nbsp;&nbsp;Evaluates&nbsp;expr&nbsp;and&nbsp;prints&nbsp;the&nbsp;time&nbsp;it&nbsp;took.&nbsp;&nbsp;Returns&nbsp;the&nbsp;value&nbsp;of<br />
&nbsp;expr.<br />
nil</div>
<br />
&nbsp; &nbsp; time宏用的不是currentTimeMillis方法，而是JDK5引入的nanoTime方法更精确。重写bench函数：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(defn&nbsp;bench&nbsp;[sum&nbsp;n]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(time&nbsp;(dotimes&nbsp;[_&nbsp;n]&nbsp;(apply&nbsp;sum&nbsp;(range&nbsp;0&nbsp;(+&nbsp;n&nbsp;1))))))<br />
#'user/bench<br />
<br />
user=&gt;&nbsp;(bench&nbsp;sum1&nbsp;10000)<br />
"Elapsed&nbsp;time:&nbsp;5425.074&nbsp;msecs"<br />
nil<br />
user=&gt;&nbsp;(bench&nbsp;sum2&nbsp;10000)<br />
"Elapsed&nbsp;time:&nbsp;7893.412&nbsp;msecs"<br />
nil</div>
&nbsp; &nbsp; &nbsp;尽管精度不一致，仍然可以看出来sum1比sum2快。<br />
&nbsp; &nbsp;&nbsp;<br />
&nbsp; &nbsp; &nbsp;这样的测试仍然是比较粗糙的，真正的性能测试需要考虑到JVM JIT、warm up以及gc带来的影响，例如我们可能需要预先执行函数多少次来让JVM&#8220;预热&#8221;这些代码。庆幸的是clojure世界里有一个开源库<span style="color: #333333; font-family: Helvetica, arial, freesans, clean, sans-serif; line-height: 22px; background-color: #ffffff; ">Criterium帮你自动搞定这一切，它的项目主页也在github上：</span><a href="https://github.com/hugoduncan/criterium">https://github.com/hugoduncan/criterium
</a><br />
<br />
&nbsp; &nbsp; &nbsp;首先在你的项目里添加criterium依赖：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->:dependencies&nbsp;[[org.clojure/clojure&nbsp;"1.3.0"]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[criterium&nbsp;"0.2.0"]])</div>
&nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp;接下来引用criterium.core这个ns，因为criterium主要宏也叫bench，因此我们原来的bench函数不能用了，换个名字叫bench-sum:<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->user=&gt;&nbsp;(use&nbsp;'criterium.core)<br />
nil<br />
user=&gt;&nbsp;(defn&nbsp;bench-sum&nbsp;[sum&nbsp;n]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(with-progress-reporting&nbsp;(bench&nbsp;(apply&nbsp;sum&nbsp;(range&nbsp;0&nbsp;(+&nbsp;1&nbsp;n)))&nbsp;:verbose)))<br />
#'user/bench-sum</div>
<br />
&nbsp; &nbsp; &nbsp;调用criterium的<strong>bench</strong>宏执行测试，使用<strong>with-progress-reporting</strong>宏包装测试代码并汇报测试进展，测试进展会打印在标准输出上。请注意，我这里并没有利用dotimes做循环测试，因为criterium会自己计算应该运行的循环次数，我们并不需要明确指定，测试下结果：<br />
<div style="font-size: 13px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; border-image: initial; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><strong>user=&gt;&nbsp;(bench-sum&nbsp;sum1&nbsp;10000)</strong><br />
Cleaning&nbsp;JVM&nbsp;allocations&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Warming&nbsp;up&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;JIT&nbsp;optimisations&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Estimating&nbsp;execution&nbsp;count&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Running&nbsp;with&nbsp;sample-count&nbsp;60&nbsp;exec-count&nbsp;1417&nbsp;<br />
Checking&nbsp;GC<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Cleaning&nbsp;JVM&nbsp;allocations&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Finding&nbsp;outliers&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Bootstrapping&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Checking&nbsp;outlier&nbsp;significance<br />
x86_64&nbsp;Mac&nbsp;OS&nbsp;X&nbsp;10.7.3&nbsp;4&nbsp;cpu(s)<br />
Java&nbsp;HotSpot(TM)&nbsp;64-Bit&nbsp;Server&nbsp;VM&nbsp;20.4-b02-402<br />
Runtime&nbsp;arguments:&nbsp;-Dclojure.compile.path=/Users/apple/programming/avos/logdashboard/test/classes&nbsp;-Dtest.version=1.0.0-SNAPSHOT&nbsp;-Dclojure.debug=<span style="color: #0000FF; ">false</span><br />
Evaluation&nbsp;count&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;85020<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Execution&nbsp;time&nbsp;mean&nbsp;:&nbsp;722.730169&nbsp;us&nbsp;&nbsp;95.0%&nbsp;CI:&nbsp;(722.552670&nbsp;us,&nbsp;722.957586&nbsp;us)<br />
&nbsp;&nbsp;&nbsp;&nbsp;Execution&nbsp;time&nbsp;std-deviation&nbsp;:&nbsp;1.042966&nbsp;ms&nbsp;&nbsp;95.0%&nbsp;CI:&nbsp;(1.034972&nbsp;ms,&nbsp;1.054015&nbsp;ms)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Execution&nbsp;time&nbsp;lower&nbsp;ci&nbsp;:&nbsp;692.122089&nbsp;us&nbsp;&nbsp;95.0%&nbsp;CI:&nbsp;(692.122089&nbsp;us,&nbsp;692.260198&nbsp;us)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Execution&nbsp;time&nbsp;upper&nbsp;ci&nbsp;:&nbsp;768.239944&nbsp;us&nbsp;&nbsp;95.0%&nbsp;CI:&nbsp;(768.239944&nbsp;us,&nbsp;768.305222&nbsp;us)<br />
<br />
Found&nbsp;2&nbsp;outliers&nbsp;in&nbsp;60&nbsp;samples&nbsp;(3.3333&nbsp;%)<br />
&nbsp;&nbsp;&nbsp;&nbsp;low-severe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2&nbsp;(3.3333&nbsp;%)<br />
&nbsp;Variance&nbsp;from&nbsp;outliers&nbsp;:&nbsp;25.4066&nbsp;%&nbsp;Variance&nbsp;is&nbsp;moderately&nbsp;inflated&nbsp;by&nbsp;outliers<br />
nil<br />
<br />
<br />
<strong>user=&gt;&nbsp;(bench-sum&nbsp;sum2&nbsp;10000)</strong><br />
Cleaning&nbsp;JVM&nbsp;allocations&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Warming&nbsp;up&nbsp;<span style="color: #0000FF; ">for</span>&nbsp;JIT&nbsp;optimisations&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Estimating&nbsp;execution&nbsp;count&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Running&nbsp;with&nbsp;sample-count&nbsp;60&nbsp;exec-count&nbsp;917&nbsp;<br />
Checking&nbsp;GC<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Cleaning&nbsp;JVM&nbsp;allocations&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Finding&nbsp;outliers&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Bootstrapping&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />
Checking&nbsp;outlier&nbsp;significance<br />
x86_64&nbsp;Mac&nbsp;OS&nbsp;X&nbsp;10.7.3&nbsp;4&nbsp;cpu(s)<br />
Java&nbsp;HotSpot(TM)&nbsp;64-Bit&nbsp;Server&nbsp;VM&nbsp;20.4-b02-402<br />
Runtime&nbsp;arguments:&nbsp;-Dclojure.compile.path=/Users/apple/programming/avos/logdashboard/test/classes&nbsp;-Dtest.version=1.0.0-SNAPSHOT&nbsp;-Dclojure.debug=<span style="color: #0000FF; ">false</span><br />
Evaluation&nbsp;count&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;55020<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Execution&nbsp;time&nbsp;mean&nbsp;:&nbsp;1.070884&nbsp;ms&nbsp;&nbsp;95.0%&nbsp;CI:&nbsp;(1.070587&nbsp;ms,&nbsp;1.071136&nbsp;ms)<br />
&nbsp;&nbsp;&nbsp;&nbsp;Execution&nbsp;time&nbsp;std-deviation&nbsp;:&nbsp;1.057659&nbsp;ms&nbsp;&nbsp;95.0%&nbsp;CI:&nbsp;(1.050688&nbsp;ms,&nbsp;1.062877&nbsp;ms)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Execution&nbsp;time&nbsp;lower&nbsp;ci&nbsp;:&nbsp;1.024195&nbsp;ms&nbsp;&nbsp;95.0%&nbsp;CI:&nbsp;(1.024164&nbsp;ms,&nbsp;1.024195&nbsp;ms)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Execution&nbsp;time&nbsp;upper&nbsp;ci&nbsp;:&nbsp;1.145664&nbsp;ms&nbsp;&nbsp;95.0%&nbsp;CI:&nbsp;(1.145664&nbsp;ms,&nbsp;1.145741&nbsp;ms)<br />
<br />
Found&nbsp;1&nbsp;outliers&nbsp;in&nbsp;60&nbsp;samples&nbsp;(1.6667&nbsp;%)<br />
&nbsp;&nbsp;&nbsp;&nbsp;low-severe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;(1.6667&nbsp;%)<br />
&nbsp;Variance&nbsp;from&nbsp;outliers&nbsp;:&nbsp;19.0208&nbsp;%&nbsp;Variance&nbsp;is&nbsp;moderately&nbsp;inflated&nbsp;by&nbsp;outliers<br />
nil</div>
<br />
<br />
&nbsp; &nbsp; 这个报告是不是相当专业？不是搞统计还不一定读的懂。大概解读下，sample-count是取样次数，默认是60次，exec-count是测试的执行次数（不包括前期warm up和JIT在内），CI是可信区间，这里取95％，Execution time mean是平均执行时间，而lower和upper是测试过程中执行时间的最小和最大值。而outliers是这一组测试中的异常值，比如执行sum1测试发现了2组异常结果。从结果来看,sum1的平均执行时间是722微秒，而sum2的平均执行时间是1.07毫秒，因此还是sum1更快一些。<br />
<br />
&nbsp; &nbsp; 总结下，如果只是在开发过程中做一些小块代码的简单测试，可以直接利用内置的time宏，如果你希望做一次比较标准的性能测试，那么就应该利用<a href="https://github.com/hugoduncan/criterium">criterium</a>这个优秀的开源库。<img src ="http://www.blogjava.net/killme2008/aggbug/372489.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> 2012-03-22 21:14 <a href="http://www.blogjava.net/killme2008/archive/2012/03/22/372489.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：API文档生成</title><link>http://www.blogjava.net/killme2008/archive/2012/03/21/372409.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 21 Mar 2012 14:24:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/03/21/372409.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/372409.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/03/21/372409.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/372409.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/372409.html</trackback:ping><description><![CDATA[<br />
&nbsp; &nbsp; 继续Clojure世界之旅，介绍下我今天的探索成果，使用clojure生成clojure项目的API文档。在java里，我们是利用javadoc生成API文档，各种build工具都提供了集成，例如maven和ant都提供了javadoc插件或者task。在Clojure世界里，同样有一系列工具帮助你从源码中自动化生成API文档。今天主要介绍三个工具。不过我不会介绍怎么在clojure里写doc，具体怎么做请看一些开源项目，或者直接看clojure.core的源码。<br />
<br />
&nbsp; &nbsp; 首先是<a href="https://github.com/weavejester/codox">codox</a>，使用相当简单，我们这里都假设你使用<a href="https://github.com/technomancy/leiningen">Leiningen</a>作为构建工具，在project.clj里添加codox依赖：<br />
<div style="font-size: 13px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #cccccc; border-right-color: #cccccc; border-bottom-color: #cccccc; border-left-color: #cccccc; border-image: initial; padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; background-color: #eeeeee; "><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->&nbsp; :dev-dependencies&nbsp;&nbsp;&nbsp;&nbsp;[[codox&nbsp;"0.5.0"]]</div>
<br />
&nbsp; &nbsp; 解下执行<strong><em>lein doc</em></strong>命令即可生成文档，生成的文档放在doc目录，在浏览器里打开index.html即可观察生成的文档。我给<a href="https://github.com/killme2008/clojure-control">clojure-control</a>生成的codox文档可以看<a href="http://fnil.net/docs/control/index.html">这个链接</a>，效果还是不错的。<br />
<br />
&nbsp; &nbsp; 第二个要介绍的工具是<a href="https://github.com/fogus/marginalia">marginalia</a>，使用方法类似codox，首先还是添加依赖：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->:dev-dependencies&nbsp;[lein-marginalia&nbsp;"0.7.0"]</div>
&nbsp; &nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;执行lein deps处理依赖关系，然后执行<strong><em>lein&nbsp;</em></strong><span style="font-family: 'Bitstream Vera Sans Mono', Courier, monospace; line-height: normal; color: #333333; "><strong><em>marg</em></strong>命令即可在docs目录生成文档，与codox不同的是marginalia只生成一个html文件，没有带js和css，但是效果也不错，可以看我给clojure-control生成的<a href="http://fnil.net/docs/control/uberdoc.html">marg文档链接</a>。</span><span style="color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; line-height: normal; ">marginalia生成的文档说明和源码左右对照，很利于阅读源码。<br />
<br />
&nbsp; &nbsp;最后要介绍的就是Clojure.org自己在使用的<a href="https://github.com/tomfaulhaber/autodoc">autodoc</a>，如果你喜欢clojure.org上的API文档格式可以采用这个工具。并且autodoc可以跟github pages结合起来，生成完整的项目文档并展示在github上。例如以clojure-control为例来介绍整个过程。首先你需要配置你的github pages，参照这个链接</span><a href="http://pages.github.com/">http://pages.github.com/</a>。<span style="color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; line-height: normal; "><br />
</span><span style="color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; line-height: normal; ">
<br />
&nbsp; &nbsp; 第一步，仍然是在project.clj添加依赖：<br />
</span>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->:dev-dependencies&nbsp;[[lein-autodoc&nbsp;"0.9.0"]]</div>
&nbsp; &nbsp; &nbsp; &nbsp;第二步，在你的.gitignore里忽略autodoc目录：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->autodoc<span style="color: #008000; ">/**</span></div>
&nbsp; &nbsp; &nbsp; &nbsp;将这些更改提交到github上，接下来在你的项目目录clone一份项目源码到&lt;project&gt;/autodoc目录：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->&nbsp;git&nbsp;clone&nbsp;git@github.com:&lt;user&nbsp;name&gt;/&lt;project&nbsp;name&gt;.git&nbsp;autodoc</div>
&nbsp; &nbsp; &nbsp; &nbsp;进入autodoc目录，执行下列命令创建一个<span style="line-height: normal; ">gh-pages分支：<br />
</span>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->&nbsp;$&nbsp;cd&nbsp;autodoc<br />
&nbsp;$&nbsp;git&nbsp;symbolic-ref&nbsp;HEAD&nbsp;refs/heads/gh-pages<br />
&nbsp;$&nbsp;rm&nbsp;.git/index<br />
&nbsp;$&nbsp;git&nbsp;clean&nbsp;-fdx<br />
&nbsp;$&nbsp;cd&nbsp;..</div>
&nbsp; &nbsp; &nbsp;回到项目根目录后，执行<strong><em>lein autodoc</em></strong>命令在autodoc目录生成文档：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->lein&nbsp;autodoc</div>
&nbsp; &nbsp; &nbsp;接下来将生成的文档推送到github分支上：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all">&nbsp;$cd autodoc&nbsp;<br />
&nbsp;$&nbsp;git&nbsp;add&nbsp;-A<br />
&nbsp;$&nbsp;git&nbsp;commit&nbsp;-m"Documentation&nbsp;update"<br />
&nbsp;$&nbsp;git&nbsp;push&nbsp;origin&nbsp;gh-pages</div>
&nbsp; &nbsp; 等上几分钟，让github渲染你的文档，最终的效果看这个链接&nbsp;<a href="http://killme2008.github.com/clojure-control">http://killme2008.github.com/clojure-control
</a>&nbsp; &nbsp;&nbsp;<br />&nbsp; &nbsp; autodoc和<span style="color: #333333; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; line-height: normal; ">marginalia都支持maven，具体使用请看他们的文档。</span><img src ="http://www.blogjava.net/killme2008/aggbug/372409.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> 2012-03-21 22:24 <a href="http://www.blogjava.net/killme2008/archive/2012/03/21/372409.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure-Control 0.3.0 is out</title><link>http://www.blogjava.net/killme2008/archive/2012/02/18/370260.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 18 Feb 2012 14:08:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/02/18/370260.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/370260.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/02/18/370260.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/370260.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/370260.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; <font><a href="https://github.com/killme2008/clojure-control" target="_blank">Clojure-control</a> is a clojure DSL for system admin and deployment with many remote machines via ssh.&nbsp; <br /></font><font>&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; I am pleased to annoucment that clojure-control 0.3.0 is out.It adds some&nbsp; powerful features in this release ,includes:<br />
</font><ul><li><font>ssh and scp both have a new option :sudo&nbsp; to be executed as root on remote machines,for example:<br /></font><pre style="font-family:arial,helvetica,sans-serif"><font><code>(ssh "/etc/init.d/ssh restart" :sudo true)</code></font></pre>
</li><li><font>scp has a new&nbsp; option :mode to change file modes copied from local:&nbsp; <br /></font><pre style="font-family:arial,helvetica,sans-serif"><font><code>(scp "start.sh" "/etc/init.d/start.sh" :sudo true :mode 755)</code></font></pre>
</li><li><font>A&nbsp; new function "exists?" to test if a file exists on remote machines:&nbsp;&nbsp; <br /></font><pre style="font-family:arial,helvetica,sans-serif"><font><code>(if (not (exists? (str "/home/deploy/.ssh")))
      (ssh (sudo (str "mkdir -p /home/deploy/.ssh"))))</code></font></pre></li><li><font>Call other task in deftask with "call" function:</font><pre style="font-family:arial,helvetica,sans-serif"><font><code>(deftask :ps "A task to grep process" [process]
        (ssh (str "ps aux | grep " process)))
(deftask :start_ha []
        (ssh "/etc/init.d/haproxy start")
        (call :ps "haproxy"))</code></font></pre></li><li><font>A new function "append" to append a line to a file on remote machines:<br /></font><pre style="font-family:arial,helvetica,sans-serif"><font><code>(ssh (append "/etc/hosts" "192.168.1.100 web" :sudo true))</code></font></pre>
</li><li><font>A new function "sed" to replace lines in a file on remote machines,and comm/uncomm to comment/uncomment a line in a file:<br /></font><pre><font><code>      <span style="font-family:arial,helvetica,sans-serif">(sed &lt;file&gt; &lt;before&gt; &lt;after&gt; :flags &lt;flags&gt; :limit &lt;limit&gt; :backup &lt;backup&gt;)</span>
</code></font></pre>

<p><font>Equivalent to</font></p>

<pre style="font-family:arial,helvetica,sans-serif"><font><code>      sed -i&lt;backup&gt; -r -e "&lt;limit&gt; s/&lt;before&gt;/&lt;after&gt;/&lt;flags&gt;g &lt;filename&gt;"</code></font></pre></li><li><pre><font>Limits max output line to 10000.</font></pre>
</li><li><pre><font>Adds more documents in wiki: <span></span><a href="http://goog_909345399/" target="_blank">https://github.com/killme2008/<wbr>clojure-control/wiki</a><code><a> </a></code></font></pre></li></ul><font>&nbsp;&nbsp; You can install the new version by :<br />
</font>
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp; lein&nbsp;plugin&nbsp;install&nbsp;control&nbsp;</span><span style="color: #000000; ">0.3</span><span style="color: #000000; ">.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">#</span><span style="color: #008000; ">For&nbsp;clojure&nbsp;1.3</span><span style="color: #008000; "><br />
</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp; lein&nbsp;plugin&nbsp;install&nbsp;control&nbsp;</span><span style="color: #000000; ">0.3</span><span style="color: #000000; ">.</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">#</span><span style="color: #008000; ">For&nbsp;clojure&nbsp;1.2</span></div><font><code><br />&nbsp;&nbsp;&nbsp; More information please visit it on github: <a href="https://github.com/killme2008/clojure-control" target="_blank">https://github.com/killme2008/<wbr>clojure-control</a> </code><code></code></font><img src ="http://www.blogjava.net/killme2008/aggbug/370260.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> 2012-02-18 22:08 <a href="http://www.blogjava.net/killme2008/archive/2012/02/18/370260.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：XML处理</title><link>http://www.blogjava.net/killme2008/archive/2012/02/18/370233.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 18 Feb 2012 04:21:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/02/18/370233.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/370233.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/02/18/370233.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/370233.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/370233.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; XML处理也是个常见的编程工作，虽然说在Clojure里你很少使用XML做配置文件，但是跟遗留系统集成或者处理和其他系统通讯，可能都需要处理XML。<br /><br />&nbsp;&nbsp;&nbsp; Clojure的标准库clojure.xml就是用来干这个事情的。一个简单的例子如下，首先我们要解析的是下面这个简单的XML：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">&lt;?</span><span style="color: #FF00FF; ">xml&nbsp;version="1.0"&nbsp;encoding="UTF-8"</span><span style="color: #0000FF; ">?&gt;</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">books</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">book</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">title</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; ">The&nbsp;joy&nbsp;of&nbsp;clojure</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">title</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">author</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; ">Michael&nbsp;Fogus&nbsp;/&nbsp;Chris&nbsp;House</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">author</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">book</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">book</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">title</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; ">Programming&nbsp;clojure</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">title</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">author</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; ">Stuart&nbsp;Halloway</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">author</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">book</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">book</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">title</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; ">Practical&nbsp;clojure</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">title</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">author</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; ">Luke&nbsp;Van&nbsp;der&nbsp;Hart</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">author</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">book</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">books</span><span style="color: #0000FF; ">&gt;</span></div><br />&nbsp;&nbsp;&nbsp; 解析xml用clojure.xml/parse方法即可，该方法返回一个clojure.xml/element这个struct-map组成的一棵树：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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;(use&nbsp;</span><span style="color: #800000; ">'</span><span style="color: #800000; ">[clojure.xml])</span><span style="color: #800000; "><br /></span><span style="color: #000000; ">nil<br />user</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;(parse&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">test.xml</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)<br />{:tag&nbsp;:books,&nbsp;:attrs&nbsp;nil,&nbsp;:content <br />&nbsp;[{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">The&nbsp;joy&nbsp;of&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Michael&nbsp;Fogus&nbsp;/&nbsp;Chris&nbsp;House</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]} <br />&nbsp;{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Programming&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Stuart&nbsp;Halloway</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]} <br />&nbsp;{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Practical&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Luke&nbsp;Van&nbsp;der&nbsp;Hart</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]}]}</span></div><br />这是一个嵌套的数据结构，每个节点都是clojure.xml/element结构，element包括：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(defstruct&nbsp;element&nbsp;:tag&nbsp;:attrs&nbsp;:content)</span></div>&nbsp;&nbsp; tag、attrs和content属性，tag就是该节点的标签，attrs是一个属性的map，而content是它的内容或者子节点。element是一个struct map，它也定义了三个方法来分别获取这三个属性：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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; ">def</span><span style="color: #000000; ">&nbsp;x&nbsp;(parse&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">test.xml</span><span style="color: #800000; ">"</span><span style="color: #000000; ">))<br /></span><span style="color: #008000; ">#</span><span style="color: #008000; ">'user/x</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">user</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;(tag&nbsp;x)<br />:books<br />user</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;(attrs&nbsp;x)<br />nil<br />user</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;(content&nbsp;x)<br />[{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">The&nbsp;joy&nbsp;of&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Michael&nbsp;Fogus&nbsp;/&nbsp;Chris&nbsp;House</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]} <br />{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Programming&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Stuart&nbsp;Halloway</span><span style="color: #800000; ">"</span><span style="color: #000000;">]}]} <br />{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Practical&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Luke&nbsp;Van&nbsp;der&nbsp;Hart</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]}]</span></div>&nbsp;&nbsp; books节点是root node，它的content就是三个book子节点，子节点组织成一个vector，我们可以随意操作：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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;(tag&nbsp;(first&nbsp;(content&nbsp;x)))<br />:book<br />user</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;(content&nbsp;(first&nbsp;(content&nbsp;x)))<br />[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">The&nbsp;joy&nbsp;of&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Michael&nbsp;Fogus&nbsp;/&nbsp;Chris&nbsp;House</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]<br />user</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;(content&nbsp;(first&nbsp;(content&nbsp;(first&nbsp;(content&nbsp;x)))))<br />[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">The&nbsp;joy&nbsp;of&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]</span></div><br />&nbsp;&nbsp;&nbsp;&nbsp; 额外提下，clojure.xml是利用SAX API做解析的。同样它还有个方法，可以将解析出来的结构还原成xml，通过emit：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">user=&gt;&nbsp;(emit&nbsp;x)<br /><br /></span><span style="color: #0000FF; ">&lt;?</span><span style="color: #FF00FF; ">xml&nbsp;version='1.0'&nbsp;encoding='UTF-8'</span><span style="color: #0000FF; ">?&gt;</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">books</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">book</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">title</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />The&nbsp;joy&nbsp;of&nbsp;clojure<br /></span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">title</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">author</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />Michael&nbsp;Fogus&nbsp;/&nbsp;Chris&nbsp;House<br /></span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">author</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">book</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">book</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br /><img src="http://www.blogjava.net/Images/dot.gif" alt="" /></span></div><br />&nbsp;&nbsp;&nbsp;&nbsp; 如果你要按照深度优先的顺序遍历xml，可以利用xml-seq将解析出来的树构成一个按照深度优先顺序排列节点的LazySeq，接下来就可以按照seq的方式处理，比如利用for来过滤节点：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">user=&gt;&nbsp;(for&nbsp;[node&nbsp;(xml-seq&nbsp;x)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>:when&nbsp;(=&nbsp;:author&nbsp;(:tag&nbsp;node))</strong>]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(first&nbsp;(:content&nbsp;node)))<br />("Michael&nbsp;Fogus&nbsp;/&nbsp;Chris&nbsp;House"&nbsp;"Stuart&nbsp;Halloway"&nbsp;"Luke&nbsp;Van&nbsp;der&nbsp;Hart")</span></div><br />&nbsp;&nbsp;&nbsp; 通过:when指定了条件，要求节点的tag是author，这样就可以查找出所有的author节点的content，是不是很方便？就像写英语描述一样。<br /><br />&nbsp;&nbsp;&nbsp; 更进一步，如果你想操作parse解析出来的这棵树，你还可以利用clojure.zip这个标准库，它有xml-zip函数将xml转换成zipper结构，并提供一系列方法来操作这棵树：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><strong><span style="color: #000000; ">user</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">(</span><span style="color: #0000FF; ">def</span><span style="color: #000000; ">&nbsp;xz&nbsp;(xml</span><span style="color: #000000; ">-</span></strong><span style="color: #000000; "><strong>zip&nbsp;x))</strong><br /></span><span style="color: #008000; ">#</span><span style="color: #008000; ">'user/xz</span><span style="color: #008000; "><br /></span><strong><span style="color: #000000; ">user</span><span style="color: #000000; ">=&gt;</span></strong><span style="color: #000000; "><strong>&nbsp;(node&nbsp;(down&nbsp;xz))</strong><br />{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">The&nbsp;joy&nbsp;of&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Michael&nbsp;Fogus&nbsp;/&nbsp;Chris&nbsp;House</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]}<br /><strong>user</strong></span><strong><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">-&gt;</span></strong><span style="color: #000000; "><strong>&nbsp;xz&nbsp;down&nbsp;right&nbsp;node)</strong><br />{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Programming&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Stuart&nbsp;Halloway</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]}<br /><strong>user</strong></span><strong><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">-&gt;</span></strong><span style="color: #000000; "><strong>&nbsp;xz&nbsp;down&nbsp;right&nbsp;right&nbsp;node)</strong><br />{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Practical&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Luke&nbsp;Van&nbsp;der&nbsp;Hart</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]}<br /><strong>user</strong></span><strong><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">-&gt;</span></strong><span style="color: #000000; "><strong>&nbsp;xz&nbsp;down&nbsp;right&nbsp;right&nbsp;lefts)</strong><br />({:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">The&nbsp;joy&nbsp;of&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Michael&nbsp;Fogus&nbsp;/&nbsp;Chris&nbsp;House</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]} <br />&nbsp;{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Programming&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Stuart&nbsp;Halloway</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]})<br /></span></div><br />&nbsp; 是不是酷得一塌糊涂？可以通过up,down,left,right,lefts,rights,来查找节点的邻近节点，可以通过node来得到节点本身。一切显得那么自然。更进一步，你还可以&#8220;编辑&#8220;这棵树，比如删除The joy of clojure这本书：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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;&nbsp;(</span><span style="color: #0000FF; ">def</span><span style="color: #000000; ">&nbsp;loc</span><span style="color: #000000; ">-</span><span style="color: #0000FF; ">in</span><span style="color: #000000; ">-</span><span style="color: #000000; ">new</span><span style="color: #000000; ">-</span><span style="color: #000000; ">tree&nbsp;(remove&nbsp;(down&nbsp;xz)))<br /></span><span style="color: #008000; ">#</span><span style="color: #008000; ">'user/loc-in-new-tree</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">user</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;(root&nbsp;loc</span><span style="color: #000000; ">-</span><span style="color: #0000FF; ">in</span><span style="color: #000000; ">-</span><span style="color: #000000; ">new</span><span style="color: #000000; ">-</span><span style="color: #000000; ">tree)<br />{:tag&nbsp;:books,&nbsp;:attrs&nbsp;nil,&nbsp;:content <br />[{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Programming&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Stuart&nbsp;Halloway</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]} <br />{:tag&nbsp;:book,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[{:tag&nbsp;:title,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Practical&nbsp;clojure</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}&nbsp;{:tag&nbsp;:author,&nbsp;:attrs&nbsp;nil,&nbsp;:content&nbsp;[</span><span style="color: #800000; ">"</span><span style="color: #800000; ">Luke&nbsp;Van&nbsp;der&nbsp;Hart</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]}]}]}</span></div><br />&nbsp;&nbsp; ok,只剩下两本书了，更多方法还包括replace做替换，edit更改节点等。因此编辑XML并重新生成，你一般可以利用clojure.zip来更改树，最后利用clojure.xml/emit将更改还原为xml。<br /><br />&nbsp;&nbsp;&nbsp; 生成xml除了emit方法，还有一个contrib库，也就是<a href="http://richhickey.github.com/clojure-contrib/prxml-api.html">prxml</a>，这个库的clojure 1.3版本有人维护了一个分支，在<a href="https://github.com/weissjeffm/clojure.prxml">这里</a>。主要方法就是prxml，它可以将clojure的数据结构转换成xml：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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; ">(prxml&nbsp;[:p&nbsp;[:raw!&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">&lt;i&gt;here&nbsp;&amp;&nbsp;gone&lt;/i&gt;</span><span style="color: #800000; ">"</span><span style="color: #000000; ">]])<br /></span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">p</span><span style="color: #000000; ">&gt;&lt;</span><span style="color: #000000; ">i</span><span style="color: #000000; ">&gt;</span><span style="color: #000000; ">here&nbsp;</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">&nbsp;gone</span><span style="color: #000000; ">&lt;/</span><span style="color: #000000; ">i</span><span style="color: #000000; ">&gt;&lt;/</span><span style="color: #000000; ">p</span><span style="color: #000000; ">&gt;</span></div>&nbsp;&nbsp;&nbsp; 显然，它也可以用于生成HTML。<br /><br />&nbsp;&nbsp;&nbsp; xpath的支持可以使用<a href="https://github.com/kyleburton/clj-xpath">clj-xpath</a>这个开源库，遗憾的是它目前仅支持clojure 1.2。<br /><br />&nbsp;&nbsp;&nbsp; 转载请注明出处：<a href="http://www.blogjava.net/killme2008/archive/2012/02/18/370233.html">http://www.blogjava.net/killme2008/archive/2012/02/18/370233.html</a>&nbsp;&nbsp;&nbsp;<img src ="http://www.blogjava.net/killme2008/aggbug/370233.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> 2012-02-18 12:21 <a href="http://www.blogjava.net/killme2008/archive/2012/02/18/370233.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：文件IO</title><link>http://www.blogjava.net/killme2008/archive/2012/02/16/370144.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 16 Feb 2012 14:38:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/02/16/370144.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/370144.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/02/16/370144.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/370144.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/370144.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 文件读写是日常编程中最经常使用的操作之一。这篇blog将大概介绍下Clojure里对文件操作的常用类库。<br /><br />&nbsp;&nbsp;&nbsp; 首先介绍标准库<a href="http://richhickey.github.com/clojure/clojure.java.io-api.html">clojure.java.io</a>，这是最经常用的IO库，定义了常见的IO操作。<br /><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;">(ns&nbsp;io<br />&nbsp;&nbsp;(:use&nbsp;[clojure.java.io]))<br /><br />;;file函数，获取一个java.io.File对象<br />(</span><span style="color: #0000FF; ">def</span><span style="color: #000000; ">&nbsp;f&nbsp;(file&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">a.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">))<br /><br />;;拷贝文件使用copy<br />(copy&nbsp;f&nbsp;(file&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">b.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">))<br /><br />;;删除文件，使用delete</span><span style="color: #000000; ">-</span><span style="color: #000000; ">file<br />(delete</span><span style="color: #000000; ">-</span><span style="color: #000000; ">file&nbsp;f)<br /><br />;;更经常使用reader和writer<br />(</span><span style="color: #0000FF; ">def</span><span style="color: #000000; ">&nbsp;rdr&nbsp;(reader&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">b.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">&nbsp;:encoding&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">utf-8</span><span style="color: #800000; ">"</span><span style="color: #000000; ">))<br />(</span><span style="color: #0000FF; ">def</span><span style="color: #000000; ">&nbsp;wtr&nbsp;(writer&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">c.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">&nbsp;:append&nbsp;true))<br /><br />;;copy可以接受多种类型的参数<br />(copy&nbsp;rdr&nbsp;wtr&nbsp;:buffer</span><span style="color: #000000; ">-</span><span style="color: #000000; ">size&nbsp;</span><span style="color: #000000; ">4096</span><span style="color: #000000; ">)<br /><br />;;关闭文件<br />(.close&nbsp;wtr)<br />(.close&nbsp;rdr)<br /><br /><br /></span></div><br />&nbsp;&nbsp;&nbsp; 这个例子基本上说明了大多数常见的操作。但是有些问题需要解释下。<br /><br />&nbsp;&nbsp;&nbsp; 首先，通过file这个函数可以将各种类型的对象转化为java.io.File对象，file可以接受String,URL,URI以及java.io.File本身作为参数，并返回java.io.File。有了File对象，你就可以调用java.io.File类中的各种方法，比如判断文件是否存在：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(.exists&nbsp;(file&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">a.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">))&nbsp;</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;true&nbsp;</span><span style="color: #0000FF; ">or</span><span style="color: #000000; ">&nbsp;false</span></div><br />&nbsp;&nbsp;&nbsp; 其次，可以通过delete-file来删除一个文件，它是调用File的delete方法来执行的，但是File.delete会返回一个布尔值告诉你成功还是失败，如果返回false，那么delete-file会抛出IO异常，如果你不想被这个异常打扰，可以让它&#8220;保持安静&#8221;：<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 />-->&nbsp;&nbsp;&nbsp; <span style="color: #000000; ">(delete</span><span style="color: #000000; ">-</span><span style="color: #000000; ">file&nbsp;f&nbsp;<strong>true</strong>)</span></div><br />&nbsp;&nbsp;&nbsp; 拷贝文件很简单，使用copy搞定，copy也可以很&#8220;宽容&#8221;，也可以接受多种类型的参数并帮你自动转换，input可以是InputStream, Reader, File, byte[] 或者String，而output可以是OutputStream, Writer或者File。是不是很给力？这都是通过Clojure的protocol和defmulti做到的。但是，copy并不帮你处理文件的关闭问题，假设你传入的input是一个File，output也是一个File，copy会自动帮你打开InputStream和OutputStream并建立缓冲区做拷贝，但是它不会帮你关闭这两个流，因此你要小心，如果你经常使用copy，这可能是个内存泄漏的隐患。<br /><br />&nbsp;&nbsp;&nbsp; 更常用的，我们一般都是用reader和writer函数来打开一个BufferedReader和BufferedWriter做读写，同样reader和writer也可以接受多种多样的参数类型，甚至包括Socket也可以。因为writer打开的通常是一个BufferedWriter，所以你如果用它写文件，有时候发现write之后文件还是没有内容，这是因为数据暂时写到了缓冲区里，没有刷入到磁盘，可以明确地调用(.flush wtr)来强制写入；或者在wtr关闭后系统帮你写入。reader和writer还可以传入一些配置项，如:encoding指定读写的字符串编码，writer可以指定是否为append模式等。<br /><br />&nbsp;&nbsp;&nbsp; Clojure并没有提供关闭文件的函数或者宏，你简单地调用close方法即可。clojure.java.io的设计很有原则，它不准备将java.io都封装一遍，而是提供一些最常用方法的简便wrapper供你使用。<br /><br />&nbsp;&nbsp;&nbsp; 刚才提到copy不会帮你关闭打开的文件流，但是我们可以利用with-open这个宏来自动帮你管理打开的流：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(with</span><span style="color: #000000; ">-</span><span style="color: #000000; ">open&nbsp;[rdr&nbsp;(reader&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">b.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wtr&nbsp;(writer&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">c.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)]<br />&nbsp;&nbsp;(copy&nbsp;rdr&nbsp;wtr))</span></div><br />&nbsp;&nbsp; with-open宏会自动帮你关闭在binding vector里打开的流，你不再需要自己调用close，也不用担心不小心造成内存泄漏。因此我会推荐你尽量用reader和writer结合with-open来做文件操作，而不要使用file函数。file函数应该用在一些判断是否存在，判断文件是否为目录等操作上。<br /><br />&nbsp;&nbsp;&nbsp; 在clojure.core里，还有两个最常用的函数slurp和spit，一个吃，一个吐，也就是slurp读文件，而spit写文件，他们类似Ruby的File里的read和write，用来完整地读或者写文件：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->&nbsp;&nbsp;&nbsp; <span style="color: #000000; ">(prn&nbsp;(slurp&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">c.txt</span><span style="color: #800000; ">"</span><span style="color: #000000;">))<br /></span>&nbsp;&nbsp;&nbsp; <span style="color: #000000; ">(spit&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">c.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">hello&nbsp;world</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)</span></div><br />&nbsp;&nbsp; 用法简单明了，slurp将文件完整地读出并返回字符串作为结果，它还接受:encoding参数来指定字符串编码，你猜的没错，它就是用reader和with-open实现的。spit同样很简单，将content转化为字符串写入文件，也接受:encoding和:append参数。<br /><br />&nbsp;&nbsp;&nbsp; 深度优先遍历目录，可以使用file-seq，返回一个深度优先顺序遍历的目录列表，这是一个LazySeq：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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;(file</span><span style="color: #000000; ">-</span><span style="color: #000000; ">seq&nbsp;(java.io.File.&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">.</span><span style="color: #800000; ">"</span><span style="color: #000000; ">))<br /><br /><br />(</span><span style="color: #008000; ">#</span><span style="color: #008000; ">&lt;File&nbsp;.&gt;&nbsp;#&lt;File&nbsp;./.gitignore&gt;&nbsp;#&lt;File&nbsp;./.lein-deps-sum&gt;&nbsp;#&lt;File&nbsp;./b.txt&gt;&nbsp;#&lt;File&nbsp;./c.txt&gt;&nbsp;#&lt;File&nbsp;./classes&gt; &#8943;&#8943; )<br /></span></div><br />&nbsp;&nbsp;&nbsp; 上面的介绍已经足以让你对付大多数需求了。接下来，介绍下几个开源库。首先是<a href="https://github.com/Raynes/fs/">fs</a>这个库，它封装了java.io.File类的大多数方法，让你用起来很clojure way，很舒服，例如：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(exists?&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">a.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)<br />(directory?&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">file</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)<br />(file?&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">file</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)<br />(name&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">/home/dennis/.inputrc</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)<br />(mkdir&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">/var/data</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)<br />(rename&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">a.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">b.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)<br />(</span><span style="color: #0000FF; ">def</span><span style="color: #000000; ">&nbsp;tmp&nbsp;(temp</span><span style="color: #000000; ">-</span><span style="color: #000000; ">dir))<br />(glob&nbsp;</span><span style="color: #008000; ">#</span><span style="color: #008000; ">".*test.*")</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">(chmod&nbsp;</span><span style="color: #000000; ">744</span><span style="color: #000000; ">&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">a.txt</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)<br /><br />&#8943;&#8943;</span></div><br />&nbsp;&nbsp;&nbsp; 更多介绍请看它的<a href="https://github.com/Raynes/fs/">源码</a>。读写二进制文件也是一个很常见的需求，Clojure有几个DSL库干这个事情，可以很直观地定义二进制格式来encode/decode，比如<a href="https://github.com/rosejn/byte-spec">byte-spec</a>这个库，看看它的例子：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">defspec&nbsp;basic</span><span style="color: #000000; ">-</span><span style="color: #000000; ">spec<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:a&nbsp;:int8<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:b&nbsp;:int16<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:c&nbsp;:int32<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:d&nbsp;:float32<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:e&nbsp;:float64<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:f&nbsp;:string)<br /><br />;;&nbsp;An&nbsp;object&nbsp;to&nbsp;serialize<br />(</span><span style="color: #0000FF; ">def</span><span style="color: #000000; ">&nbsp;foo&nbsp;{:a&nbsp;</span><span style="color: #000000; ">10</span><span style="color: #000000; ">&nbsp;:b&nbsp;</span><span style="color: #000000; ">20</span><span style="color: #000000; ">&nbsp;:c&nbsp;</span><span style="color: #000000; ">40</span><span style="color: #000000; ">&nbsp;:d&nbsp;</span><span style="color: #000000; ">23.2</span><span style="color: #000000; ">&nbsp;:e&nbsp;</span><span style="color: #000000; ">23.2</span><span style="color: #000000; ">&nbsp;:f&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">asddf</span><span style="color: #800000; ">"</span><span style="color: #000000; ">})<br /><br />;;&nbsp;And&nbsp;serialize&nbsp;it&nbsp;to&nbsp;a&nbsp;byte&nbsp;array&nbsp;like&nbsp;this:<br />(spec</span><span style="color: #000000; ">-</span><span style="color: #000000; ">write</span><span style="color: #000000; ">-</span><span style="color: #000000; ">bytes&nbsp;basic</span><span style="color: #000000; ">-</span><span style="color: #000000; ">spec&nbsp;foo)&nbsp;;;&nbsp;</span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;[<img src="http://www.blogjava.net/Images/dot.gif" alt="" />bytes<img src="http://www.blogjava.net/Images/dot.gif" alt="" />]<br /><br />;;&nbsp;reading&nbsp;</span><span style="color: #0000FF; ">in</span><span style="color: #000000; ">&nbsp;a&nbsp;byte&nbsp;array&nbsp;with&nbsp;the&nbsp;basic</span><span style="color: #000000; ">-</span><span style="color: #000000; ">spec&nbsp;format&nbsp;works&nbsp;like&nbsp;this:<br />(spec</span><span style="color: #000000; ">-</span><span style="color: #000000; ">read</span><span style="color: #000000; ">-</span><span style="color: #000000; ">bytes&nbsp;basic</span><span style="color: #000000; ">-</span><span style="color: #000000; ">spec&nbsp;bytes)</span></div>&nbsp;&nbsp;&nbsp; 相当直观和给力吧。<a href="https://github.com/ztellman/gloss/wiki/Introduction">Gloss</a>是一个更强大的DSL库，非常适合做网络通讯的协议处理。这里就不多做介绍了，你可以自己看它的例子和文档。<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; 转载请注明出处：<a id="Editor_Edit_hlEntryLink" title="view: Clojure世界：文件IO" href="../archive/2012/02/16/370144.html" target="_blank">http://www.blogjava.net/killme2008/archive/2012/02/16/370144.html</a><br />&nbsp;&nbsp;&nbsp;<img src ="http://www.blogjava.net/killme2008/aggbug/370144.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> 2012-02-16 22:38 <a href="http://www.blogjava.net/killme2008/archive/2012/02/16/370144.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：单元测试</title><link>http://www.blogjava.net/killme2008/archive/2012/02/15/370040.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 15 Feb 2012 11:39:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/02/15/370040.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/370040.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/02/15/370040.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/370040.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/370040.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 单元测试也是一个开发中最常见的需求，在Java里我们用JUnit或者TestNG，在clojure里也内置了单元测试的库。标准库的<a href="http://richhickey.github.com/clojure/clojure.test-api.html">clojure.test</a>，以及第三方框架<a href="https://github.com/marick/Midje">midje</a>。这里我将主要介绍clojure.test这个标准库，midje是个更加强大的测试框架，广告下，midje的介绍在第二次cn-clojure聚会上将有个Topic，我就不画蛇添足了。通常来说，clojure.test足够让你对付日常的测试。<br /><br />&nbsp;&nbsp;&nbsp; 首先看一个最简单的例子，定义一个函数square来计算平方，然后我们测试这个函数：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">;;引用clojure.test<br />(ns&nbsp;example<br />&nbsp;&nbsp;(:use&nbsp;[clojure.test&nbsp;:only&nbsp;[deftest&nbsp;</span><span style="color: #0000FF; ">is</span><span style="color: #000000; ">&nbsp;run</span><span style="color: #000000; ">-</span><span style="color: #000000; ">tests]]))<br />;;定义函数<br />(defn&nbsp;square&nbsp;[x]<br />&nbsp;&nbsp;(</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;x&nbsp;x))<br />;;测试函数<br />(deftest&nbsp;test</span><span style="color: #000000; ">-</span><span style="color: #000000; ">square </span><span style="color: #800000; "></span><span style="color: #000000; "><br />&nbsp;&nbsp;(</span><span style="color: #0000FF; ">is</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">4</span><span style="color: #000000; ">&nbsp;(square&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">)))<br />&nbsp;&nbsp;(</span><span style="color: #0000FF; ">is</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">9</span><span style="color: #000000; ">&nbsp;(square&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">3</span><span style="color: #000000; ">))))<br />;;运行测试<br />(run</span><span style="color: #000000; ">-</span><span style="color: #000000; ">tests&nbsp;</span><span style="color: #800000; ">'</span><span style="color: #800000; ">example)</span></div><br />&nbsp;&nbsp;&nbsp; 执行输出：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; "><br />Testing&nbsp;example<br /><br />Ran&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&nbsp;tests&nbsp;containing&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;assertions.<br />0&nbsp;failures,&nbsp;0&nbsp;errors.</span></div><br />&nbsp;&nbsp;&nbsp; 这个小例子基本说明了clojure.test的主要功能。<strong>首先是断言is</strong>，类似JUnit里的assertTrue，用来判断form是否为true，它还可以接受一个额外的msg参数来描述断言：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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; ">is</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">4</span><span style="color: #000000; ">&nbsp;(square&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">))&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">a&nbsp;test</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)</span></div>&nbsp;&nbsp;&nbsp; 它还有两种变形，专门用来判断测试是否抛出异常：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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; ">is</span><span style="color: #000000; ">&nbsp;(thrown?&nbsp;RuntimeException&nbsp;(square&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">a</span><span style="color: #800000; ">"</span><span style="color: #000000; ">)))<br />&nbsp;(</span><span style="color: #0000FF; ">is</span><span style="color: #000000; ">&nbsp;(thrown</span><span style="color: #000000; ">-</span><span style="color: #000000; ">with</span><span style="color: #000000; ">-</span><span style="color: #000000; ">msg?&nbsp;RuntimeException&nbsp;</span><span style="color: #008000; ">#</span><span style="color: #008000; ">"java.lang.String&nbsp;cannot&nbsp;be&nbsp;cast&nbsp;to&nbsp;java.lang.Number"&nbsp;&nbsp;(square&nbsp;"a")))</span></div>&nbsp;&nbsp;&nbsp; 上面的例子故意求"a"的平方，这会抛出一个java.lang.ClassCastException，一个运行时异常，并且异常信息为java.lang.String cannot be cast to java.lang.Number。我们可以通过上面的方式来测试这种意外情况。clojure.test还提供了另一个<strong>断言are</strong>，用来判断多个form：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;(testing&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">test&nbsp;zero&nbsp;or&nbsp;one</span><span style="color: #800000; ">"</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;(are<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;0&nbsp;(square&nbsp;0))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&nbsp;(square&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">))))</span></div>&nbsp;&nbsp;&nbsp; are接受多个form并判断是否正确。这里还用了testing这个宏来添加一段字符串来描述测试的内容。<br /><br />&nbsp;&nbsp;&nbsp; <strong>其次，我们用deftest宏定义了一个测试用例</strong>，deftest定义的测试用例也可以组合起来：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;(deftest&nbsp;addition<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000FF; ">is</span><span style="color: #000000; ">&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; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">)))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000FF; ">is</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">7</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">4</span><span style="color: #000000; ">))))<br />&nbsp;&nbsp;&nbsp;(deftest&nbsp;subtraction<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000FF; ">is</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: #000000; ">-</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">4</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">)))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000FF; ">is</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">-</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">7</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">4</span><span style="color: #000000; ">))))<br />&nbsp;&nbsp;&nbsp;(deftest&nbsp;arithmetic<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(addition)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(subtraction))</span></div><br />&nbsp;&nbsp;&nbsp; 但是组合后的tests运行就不能简单地传入一个ns，而需要定义一个test-ns-hook指定要跑的测试用例，否则组合的用例如上面的addition和subtraction会运行两次。我们马上谈到。<br /><br />&nbsp;&nbsp;&nbsp; <strong>定义完用例后是运行测试，运行测试使用run-tests</strong>，可以指定要跑测试的ns，run-tests接受可变参数个的ns。刚才提到，组合tests的时候会有重复运行的问题，要防止重复运行，可以定义一个<strong>test-ns-hook</strong>的函数：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(defn&nbsp;test</span><span style="color: #000000; ">-</span><span style="color: #000000; ">ns</span><span style="color: #000000; ">-</span><span style="color: #000000; ">hook&nbsp;[]<br />&nbsp;&nbsp;(test</span><span style="color: #000000; ">-</span><span style="color: #000000; ">square)<br />&nbsp;&nbsp;(arithmetic))</span></div>&nbsp;&nbsp;&nbsp; 这样run-tests就会调用test-ns-hook按照给定的顺序执行指定的用例，避免了重复执行。<br /><br />&nbsp;&nbsp;&nbsp; 在你的测试代码里明确调用run-tests执行测试是一种方式，不过我们在开发中更经常使用的是<a href="https://github.com/technomancy/leiningen">lein</a>来管理project，<a href="https://github.com/technomancy/leiningen">lein</a>会将src和test分开，将你的测试代码组织在专门的test目录，类似使用maven的时候我们将main和test分开一样。这时候就可以简单地调用:<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 />-->&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: #000000;">lein&nbsp;test</span></div>命令来执行单元测试，而不需要明确地在测试代码里调用run-tests并指定ns。更实用的使用例子可以看一些开源项目的组织。<br /><br />&nbsp;&nbsp;&nbsp; 单元测试里做mock也是比较常见的需求，在clojure里做mock很容易，原来clojure.contrib有个mock库，基本的原理都是利用binding来动态改变被mock对象的功能，但是在clojure 1.3里，binding只能改变标注为dynamic的变量，并且clojure.contrib被废弃，部分被合并到core里面，Allen Rohner编译了一个可以用于clojure 1.3的clojure.contrib，不过需要你自己install到本地仓库，具体看<a href="https://github.com/arohner/clojure-contrib/tree/1.3-compat">这里</a>。不过clojure.contrib.mock哪怕使用1.2的编译版本其实也是可以的。<br /><br />&nbsp;&nbsp;&nbsp; clojure.contrib最重要的是expect宏，它类似EasyMock里的expect方法，看一个例子：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(use&nbsp;[clojure.contrib.mock&nbsp;:only&nbsp;[times&nbsp;returns&nbsp;has</span><span style="color: #000000; ">-</span><span style="color: #000000; ">args&nbsp;expect]])<br /><br />(deftest&nbsp;test</span><span style="color: #000000; ">-</span><span style="color: #000000; ">square2<br />&nbsp;&nbsp;(expect&nbsp;[square&nbsp;(has</span><span style="color: #000000; ">-</span><span style="color: #000000; ">args&nbsp;[number?]&nbsp;(times&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;(returns&nbsp;</span><span style="color: #000000; ">9</span><span style="color: #000000; ">)))]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000FF; ">is</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">9</span><span style="color: #000000; ">&nbsp;(square&nbsp;</span><span style="color: #000000; ">4</span><span style="color: #000000; ">)))))</span></div><br />&nbsp;&nbsp;&nbsp; has-args用来检测square的参数是不是number，times用来指定预期调用的次数，而returns用来返回mock值，是不是很像EasyMock？因为我们这个测试只调用了square一次，所以这个用例将失败：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">Testing&nbsp;example<br /></span><span style="color: #800000; ">"</span><span style="color: #800000; ">Unexpected&nbsp;invocation&nbsp;count.&nbsp;Function&nbsp;name:&nbsp;square&nbsp;expected:&nbsp;2&nbsp;actual:&nbsp;1</span><span style="color: #800000; ">"</span></div>&nbsp;&nbsp; 这个例子要在Clojure 1.3里运行，需要将square定义成dynamic：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(defn&nbsp;</span><span style="color: #000000; ">^</span><span style="color: #000000; ">:dynamic&nbsp;square&nbsp;[x]<br />&nbsp;&nbsp;(</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;x&nbsp;x))</span></div>&nbsp;&nbsp; 否则会告诉你没办法绑定square:<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">actual:&nbsp;java.lang.IllegalStateException:&nbsp;Can</span><span style="color: #800000; ">'</span><span style="color: #800000; ">t&nbsp;dynamically&nbsp;bind&nbsp;non-dynamic&nbsp;var:&nbsp;example/square</span></div><br /><br />&nbsp;&nbsp;&nbsp; 额外提下，还有个轻量级的测试框架<a href="https://github.com/jaycfields/expectations">expections</a>可以看一下，类似Ruby Facker的<a href="https://github.com/paraseba/faker">facker</a>库提供一些常见的模拟数据，如名称地址等。<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; 转载请注明出处：<a id="Editor_Edit_hlEntryLink" title="view: Clojure世界：单元测试" href="../archive/2012/02/15/370040.html" target="_blank">http://www.blogjava.net/killme2008/archive/2012/02/15/370040.html</a><br /><br />&nbsp;&nbsp;&nbsp;<img src ="http://www.blogjava.net/killme2008/aggbug/370040.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> 2012-02-15 19:39 <a href="http://www.blogjava.net/killme2008/archive/2012/02/15/370040.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：使用rlwrap增强REPL</title><link>http://www.blogjava.net/killme2008/archive/2012/02/14/369976.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 14 Feb 2012 11:05:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/02/14/369976.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/369976.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/02/14/369976.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/369976.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/369976.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; Clojure的REPL非常方便，可以随时随地试验你的想法，REPL是read-eval-print-loop的简称。默认clojure.contrib有带一个shell脚本来启动REPL，具体看<a href="https://github.com/richhickey/clojure-contrib/blob/master/launchers/bash/clj-env-dir">这里</a>。你也可以用JLine来增强REPL：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">java&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">cp&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">%CLOJURE_DIR%\jline-VERSION.jar;%CLOJURE_JAR%</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;jline.ConsoleRunner&nbsp;clojure.main</span></div>
<br />
&nbsp;&nbsp;&nbsp; 不过，其实你还可以用<a href="http://utopia.knoware.nl/~hlub/rlwrap/#rlwrap">rlwrap</a>这个GNU库来增强clojure REPL。使用它有如下好处：<br />
1.Tab completion，使用tab做代码提示。<br />
2.括号匹配<br />
3.历史记录，哪怕你重启REPL<br />
4.通过<a href="http://tiswww.case.edu/php/chet/readline/readline.html#SEC9">.inputrc</a>来绑定vi或者emacs<br />
<br />
&nbsp;&nbsp;&nbsp; 具体操作步骤如下：<br />
<br />
1.首先，你需要在你的机器上安装rlwrap，你可以通过apt或者port,homebrew等工具安装或者自己下载安装：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">sudo&nbsp;port&nbsp;install&nbsp;rlwrap</span></div>
<br />
2.在你的home目录下创建一个clojure目录作为clojure home，并拷贝clojure.jar进去：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">mkdir&nbsp;</span><span style="color: #000000; ">~/</span><span style="color: #000000; ">clojure<br />
cp&nbsp;.m2</span><span style="color: #000000; ">/</span><span style="color: #000000; ">repository</span><span style="color: #000000; ">/</span><span style="color: #000000; ">org</span><span style="color: #000000; ">/</span><span style="color: #000000; ">clojure</span><span style="color: #000000; ">/</span><span style="color: #000000; ">clojure</span><span style="color: #000000; ">/</span><span style="color: #000000; ">1.3</span><span style="color: #000000; ">.</span><span style="color: #000000; ">0</span><span style="color: #000000; ">/</span><span style="color: #000000; ">clojure</span><span style="color: #000000; ">-</span><span style="color: #000000; ">1.3</span><span style="color: #000000; ">.</span><span style="color: #000000; ">0</span><span style="color: #000000; ">.jar&nbsp;</span><span style="color: #000000; ">~/</span><span style="color: #000000; ">clojure</span><span style="color: #000000; ">/</span><span style="color: #000000; ">clojure.jar <br />
</span></div>
我是从maven的本地仓库里拷贝了clojure 1.3的jar包过去，重命名为clojure.jar<br />
<br />
3.创建一个shell脚本名为clj，并放入你的path变量，脚本内容：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">#</span><span style="color: #000000; ">!/</span><span style="color: #000000; ">bin</span><span style="color: #000000; ">/</span><span style="color: #000000; ">sh<br />
breakchars</span><span style="color: #000000; ">=</span><span style="color: #000000; ">"</span><span style="color: #000000; ">(){}[],^%$#@\</span><span style="color: #000000; ">"</span><span style="color: #000000; ">\</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;:''|\\</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br />
CLOJURE_DIR</span><span style="color: #000000; ">=~/</span><span style="color: #000000; ">clojure<br />
CLOJURE_JAR</span><span style="color: #000000; ">=</span><span style="color: #000000; ">"</span><span style="color: #000000; ">$CLOJURE_DIR</span><span style="color: #000000; ">"</span><span style="color: #000000; ">/</span><span style="color: #000000; ">clojure.jar<br />
JAVA_OPTS</span><span style="color: #000000; ">=</span><span style="color: #000000; ">"</span><span style="color: #000000; ">-Xmx512m&nbsp;-XX:MaxPermSize=256m&nbsp;-XX:+UseConcMarkSweepGC&nbsp;-XX:+UseCMSCompactAtFullCollection&nbsp;-XX:+CMSClassUnloadingEnabled</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br />
</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;[&nbsp;$#&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">eq&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&nbsp;];&nbsp;then&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;exec&nbsp;rlwrap&nbsp;</span><span style="color: #000000; ">--</span><span style="color: #000000; ">remember&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">c&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">b&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">$breakchars</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;\<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">f&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">$HOME</span><span style="color: #000000; ">"</span><span style="color: #000000; ">/</span><span style="color: #000000; ">.clj_completions&nbsp;\<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">t&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Clojure&nbsp;REPL</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;\<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">p&nbsp;red&nbsp;\<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">H&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">$CLOJURE_DIR</span><span style="color: #000000; ">"</span><span style="color: #000000; ">/</span><span style="color: #000000; ">.repl_history&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">s&nbsp;</span><span style="color: #000000; ">1000</span><span style="color: #000000; ">\<br />
&nbsp;&nbsp;&nbsp;java&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">$JAVA_OPTS</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">cp&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">$CLOJURE_JAR</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;clojure.main<br />
</span><span style="color: #0000FF; ">else</span><span style="color: #000000; "><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exec&nbsp;java&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">cp&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">$CLOJURE_JAR</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;clojure.main&nbsp;$</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; ">"</span><span style="color: #000000; ">$@</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br />
fi</span></div>
我们将命令历史输出到~/clojure/.repl_history文件中，并限制数目为1000。<br />
<br />
4.clj脚本中通过-f选项指定了completions文件为~/.clj_completions，执行下列clojure程序生成此文件：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">(def&nbsp;completions&nbsp;(keys&nbsp;(ns</span><span style="color: #000000; ">-</span><span style="color: #000000; ">publics&nbsp;(find</span><span style="color: #000000; ">-</span><span style="color: #000000; ">ns&nbsp;'clojure.core))))<br />
;(def&nbsp;completions&nbsp;(mapcat&nbsp;(comp&nbsp;keys&nbsp;ns</span><span style="color: #000000; ">-</span><span style="color: #000000; ">publics)&nbsp;(all</span><span style="color: #000000; ">-</span><span style="color: #000000; ">ns)))<br />
(</span><span style="color: #0000FF; ">with</span><span style="color: #000000; ">-</span><span style="color: #000000; ">open&nbsp;[f&nbsp;(java.io.BufferedWriter.&nbsp;(java.io.FileWriter.&nbsp;(str&nbsp;(System</span><span style="color: #000000; ">/</span><span style="color: #000000; ">getenv&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">HOME</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">/.clj_completions</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)))]<br />
&nbsp;&nbsp;(.write&nbsp;f&nbsp;(apply&nbsp;str&nbsp;(interpose&nbsp;\newline&nbsp;completions))))</span></div>
这个程序只生成clojure.core的completions文件，如果你想将所有ns都加入进去，注释掉第一行，使用第二行程序。<br />
<br />
5.最后，配置下~/.inputrc文件：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">set&nbsp;editing</span><span style="color: #000000; ">-</span><span style="color: #000000; ">mode&nbsp;emacs<br />
tab:&nbsp;complete<br />
set&nbsp;completion</span><span style="color: #000000; ">-</span><span style="color: #000000; ">query</span><span style="color: #000000; ">-</span><span style="color: #000000; ">items&nbsp;</span><span style="color: #000000; ">150</span><span style="color: #000000; "><br />
set&nbsp;completion</span><span style="color: #000000; ">-</span><span style="color: #000000; ">ignore</span><span style="color: #000000; ">-</span><span style="color: #0000FF; ">case</span><span style="color: #000000; ">&nbsp;on<br />
set&nbsp;blink</span><span style="color: #000000; ">-</span><span style="color: #000000; ">matching</span><span style="color: #000000; ">-</span><span style="color: #000000; ">paren&nbsp;on<br />
set&nbsp;bell</span><span style="color: #000000; ">-</span><span style="color: #000000; ">style&nbsp;visible</span></div>
我绑定为emacs，你可以选择vi。<br />
<br />
6.一切搞定，接下来你可以敲入命令clj来使用rlwrap启动clojure REPL了，可以用tab做代码提示了，可以用Ctrl + r来搜索历史命令，运行截图：<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/killme2008/rlwrap.png" height="101" width="900" /><br />
<br />
参考：<a href="http://en.wikibooks.org/wiki/Clojure_Programming/Getting_Started#Enhancing_Clojure_REPL_with_rlwrap">http://en.wikibooks.org/wiki/Clojure_Programming/Getting_Started#Enhancing_Clojure_REPL_with_rlwrap</a><br />转载请注明出处：<a id="Editor_Edit_hlEntryLink" title="view: Clojure世界：使用rlwrap增强REPL" href="../archive/2012/02/14/369976.html" target="_blank">http://www.blogjava.net/killme2008/archive/2012/02/14/369976.html</a><img src ="http://www.blogjava.net/killme2008/aggbug/369976.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> 2012-02-14 19:05 <a href="http://www.blogjava.net/killme2008/archive/2012/02/14/369976.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：Http Client</title><link>http://www.blogjava.net/killme2008/archive/2012/02/13/369890.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 13 Feb 2012 10:57:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/02/13/369890.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/369890.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/02/13/369890.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/369890.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/369890.html</trackback:ping><description><![CDATA[<br />&nbsp;&nbsp;&nbsp; 使用http client提交表单或者下载网页也是非常常见的任务，比如使用Java的时候可以用标准库的HttpURLConnection，也可以选择<a href="http://hc.apache.org/">Apache Http Client</a>。在clojure里也有这样的类库，这里我将介绍三个各有特色的http client实现。<br /><br />&nbsp;&nbsp;&nbsp; 首先，我最先推荐使用clj-http这个类库，它是Apache HttpClient的clojure wrapper，是一个提供同步API的简单易用的Http Client。<br /><br />名称: clj-http<br />主页：<a href="https://github.com/dakrone/clj-http">https://github.com/dakrone/clj-http</a><br />依赖：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">[clj</span><span style="color: #000000; ">-</span><span style="color: #000000; ">http&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">0.3.1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">]</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; ">(require&nbsp;</span><span style="color: #000000; ">'</span><span style="color: #000000; ">[clj-http.client&nbsp;:as&nbsp;client])</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">get&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://google.com</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-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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; "> ｛:cookies {"NID" {:domain ".google.com.hk", :expires #&lt;Date Tue Aug 14 18:20:38 CST 2012&gt;, :path "/", :value "56=qn2OWtODE2D3fUKi_vbi44jZepOeLI9xC4Ta1JQLEicqUvIZAqr7TCmft_hq8i_FRwnFXdTK1jV2S5IrSZFyYhlAN2KcQEXgWX1iK36gM2iYPaKPihuUZDCqgiAamDOl", :version 0}, "PREF" {:domain ".google.com.hk", :expires #&lt;Date Wed Feb 12 18:20:38 CST 2014&gt;, :path "/", :value "ID=8b73a654ff0a2783:FF=0:NW=1:TM=1329128438:LM=1329128438:S=uEM4SsFuHlkqtVhp", :version 0}},<br />&nbsp;&nbsp;&nbsp; :status&nbsp;</span><span style="color: #000000; ">200</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;:headers&nbsp;{</span><span style="color: #000000; ">"</span><span style="color: #000000; ">date</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Sun,&nbsp;01&nbsp;Aug&nbsp;2010&nbsp;07:03:49&nbsp;GMT</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;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">cache-control</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">private,&nbsp;max-age=0</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;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">content-type</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">text/html;&nbsp;charset=ISO-8859-1</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;<img src="http://www.blogjava.net/Images/dot.gif" alt="" />}<br />&nbsp;&nbsp;&nbsp;&nbsp;:body&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&lt;!doctype&nbsp;html&gt;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /></span><span style="color: #000000; ">"</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;:trace</span><span style="color: #000000; ">-</span><span style="color: #000000; ">redirects&nbsp;[</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://google.com</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://www.google.com/</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://www.google.fr/</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-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">get&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://site.com/resources/3</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;{:accept&nbsp;:json})<br /><br />;;&nbsp;Various&nbsp;options:<br />(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">post&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://site.com/api</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br />&nbsp;&nbsp;{:basic</span><span style="color: #000000; ">-</span><span style="color: #000000; ">auth&nbsp;[</span><span style="color: #000000; ">"</span><span style="color: #000000; ">user</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">pass</span><span style="color: #000000; ">"</span><span style="color: #000000; ">]<br />&nbsp;&nbsp;&nbsp;:body&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">{\</span><span style="color: #000000; ">"</span><span style="color: #000000; ">json\</span><span style="color: #000000; ">"</span><span style="color: #000000; ">:&nbsp;\</span><span style="color: #000000; ">"</span><span style="color: #000000; ">input\</span><span style="color: #000000; ">"</span><span style="color: #000000; ">}</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;:headers&nbsp;{</span><span style="color: #000000; ">"</span><span style="color: #000000; ">X-Api-Version</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">}<br />&nbsp;&nbsp;&nbsp;:content</span><span style="color: #000000; ">-</span><span style="color: #000000; ">type&nbsp;:json<br />&nbsp;&nbsp;&nbsp;:socket</span><span style="color: #000000; ">-</span><span style="color: #000000; ">timeout&nbsp;</span><span style="color: #000000; ">1000</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;:conn</span><span style="color: #000000; ">-</span><span style="color: #000000; ">timeout&nbsp;</span><span style="color: #000000; ">1000</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;:accept&nbsp;:json})<br /><br />;;&nbsp;Need&nbsp;to&nbsp;contact&nbsp;a&nbsp;server&nbsp;with&nbsp;an&nbsp;untrusted&nbsp;SSL&nbsp;cert</span><span style="color: #000000; ">?</span><span style="color: #000000; "><br />(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">get&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">https://alioth.debian.org</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;{:insecure</span><span style="color: #000000; ">?</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">})<br /><br />;;&nbsp;If&nbsp;you&nbsp;don</span><span style="color: #000000; ">'</span><span style="color: #000000; ">t&nbsp;want&nbsp;to&nbsp;follow-redirects&nbsp;automatically:</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">get&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://site.come/redirects-somewhere</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;{:follow</span><span style="color: #000000; ">-</span><span style="color: #000000; ">redirects&nbsp;</span><span style="color: #0000FF; ">false</span><span style="color: #000000; ">})<br /><br />;;&nbsp;Only&nbsp;follow&nbsp;a&nbsp;certain&nbsp;number&nbsp;of&nbsp;redirects:<br />(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">get&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://site.come/redirects-somewhere</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;{:max</span><span style="color: #000000; ">-</span><span style="color: #000000; ">redirects&nbsp;</span><span style="color: #000000; ">5</span><span style="color: #000000; ">})<br /><br />;;&nbsp;Throw&nbsp;an&nbsp;exception&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;redirected&nbsp;too&nbsp;many&nbsp;times:<br />(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">get&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://site.come/redirects-somewhere</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;{:max</span><span style="color: #000000; ">-</span><span style="color: #000000; ">redirects&nbsp;</span><span style="color: #000000; ">5</span><span style="color: #000000; ">&nbsp;:</span><span style="color: #0000FF; ">throw</span><span style="color: #000000; ">-</span><span style="color: #000000; ">exceptions&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">})<br /><br />;;&nbsp;Send&nbsp;form&nbsp;params&nbsp;as&nbsp;a&nbsp;urlencoded&nbsp;body<br />(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">post&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http//site.com</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;{:form</span><span style="color: #000000; ">-</span><span style="color: #000000; ">params&nbsp;{:foo&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">bar</span><span style="color: #000000; ">"</span><span style="color: #000000; ">}})<br /><br />;;&nbsp;Multipart&nbsp;form&nbsp;uploads</span><span style="color: #000000; ">/</span><span style="color: #000000; ">posts<br />;;&nbsp;a&nbsp;map&nbsp;or&nbsp;vector&nbsp;works&nbsp;as&nbsp;the&nbsp;multipart&nbsp;object.&nbsp;Use&nbsp;a&nbsp;vector&nbsp;of<br />;;&nbsp;vectors&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;you&nbsp;need&nbsp;to&nbsp;preserve&nbsp;order,&nbsp;a&nbsp;map&nbsp;otherwise.<br />(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">post&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http//example.org</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;{:multipart&nbsp;[[</span><span style="color: #000000; ">"</span><span style="color: #000000; ">title</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">My&nbsp;Awesome&nbsp;Picture</span><span style="color: #000000; ">"</span><span style="color: #000000; ">]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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: #000000; ">"</span><span style="color: #000000; ">Content/type</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">image/jpeg</span><span style="color: #000000; ">"</span><span style="color: #000000; ">]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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: #000000; ">"</span><span style="color: #000000; ">file</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;(clojure.java.io</span><span style="color: #000000; ">/</span><span style="color: #000000; ">file&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">pic.jpg</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)]]})<br />;;&nbsp;Multipart&nbsp;values&nbsp;can&nbsp;be&nbsp;one&nbsp;of&nbsp;the&nbsp;following:<br />;;&nbsp;String,&nbsp;InputStream,&nbsp;File,&nbsp;or&nbsp;a&nbsp;</span><span style="color: #0000FF; ">byte</span><span style="color: #000000; ">-</span><span style="color: #000000; ">array<br /><br />;;&nbsp;Basic&nbsp;authentication<br />(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">get&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://site.com/protected</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;{:basic</span><span style="color: #000000; ">-</span><span style="color: #000000; ">auth&nbsp;[</span><span style="color: #000000; ">"</span><span style="color: #000000; ">user</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">pass</span><span style="color: #000000; ">"</span><span style="color: #000000; ">]})<br />(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">get&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://site.com/protected</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;{:basic</span><span style="color: #000000; ">-</span><span style="color: #000000; ">auth&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">user:pass</span><span style="color: #000000; ">"</span><span style="color: #000000; ">})<br /><br />;;&nbsp;Query&nbsp;parameters<br />(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">get&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://site.com/search</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;{:query</span><span style="color: #000000; ">-</span><span style="color: #000000; ">params&nbsp;{</span><span style="color: #000000; ">"</span><span style="color: #000000; ">q</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">foo,&nbsp;bar</span><span style="color: #000000; ">"</span><span style="color: #000000; ">}})</span></div><br />&nbsp;&nbsp;&nbsp; clj-http的API相当的简洁漂亮，使用起来非常便利，强烈推荐。题外，学习clojure的一个好方法就是为现有的java类库实现一些方便的clojure wrapper。<br /><br />&nbsp;&nbsp;&nbsp; 如果你需要异步的http client，我会推荐http.async.client这个类库，它的API是异步形式的类似 Java的Future模式，对于clojure程序员来说应该更像是agent。<br /><br />名称：http.async.client<br />主页：<a href="https://github.com/neotyk/http.async.client">https://github.com/neotyk/http.async.client</a><br />依赖：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">[http.async.client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">0.4.1</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-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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: #000000; ">'</span><span style="color: #000000; ">[http.async.client&nbsp;:as&nbsp;c])</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">(with</span><span style="color: #000000; ">-</span><span style="color: #000000; ">open&nbsp;[client&nbsp;(c</span><span style="color: #000000; ">/</span><span style="color: #000000; ">create</span><span style="color: #000000; ">-</span><span style="color: #000000; ">client)]<br />&nbsp;&nbsp;(let&nbsp;[response&nbsp;(c</span><span style="color: #000000; ">/</span><span style="color: #000000; ">GET&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://neotyk.github.com/http.async.client/</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)]<br />&nbsp;&nbsp;&nbsp;&nbsp;(prn&nbsp;(c</span><span style="color: #000000; ">/</span><span style="color: #000000; ">done</span><span style="color: #000000; ">?</span><span style="color: #000000; ">&nbsp;response))<br />&nbsp;&nbsp;&nbsp; (c</span><span style="color: #000000; ">/</span><span style="color: #000000; ">await&nbsp;response)<br />&nbsp;&nbsp;&nbsp;&nbsp;(prn&nbsp;(c</span><span style="color: #000000; ">/</span><span style="color: #000000; ">string&nbsp;response))<br />&nbsp;&nbsp;&nbsp;&nbsp;(prn&nbsp;(c</span><span style="color: #000000; ">/</span><span style="color: #000000; ">status&nbsp;response))<br />&nbsp;&nbsp;&nbsp;&nbsp;(prn&nbsp;(c</span><span style="color: #000000; ">/</span><span style="color: #000000; ">done</span><span style="color: #000000; ">?</span><span style="color: #000000; ">&nbsp;response))))</span></div><br />输出：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">false</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">&lt;!</span><span style="color: #000000; ">DOCTYPE&nbsp;html&nbsp;<img src="http://www.blogjava.net/Images/dot.gif" alt="" /><img src="http://www.blogjava.net/Images/dot.gif" alt="" /><br />{:code&nbsp;</span><span style="color: #000000; ">200</span><span style="color: #000000; ">,&nbsp;:msg&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">OK</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;:protocol&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">HTTP/1.1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;:major&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,&nbsp;:minor&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">}<br /></span><span style="color: #0000FF; ">true</span></div><br />更多例子：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(c</span><span style="color: #000000; ">/</span><span style="color: #000000; ">POST&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://example.com</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;:body&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">hello&nbsp;world</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;:timeout&nbsp;</span><span style="color: #000000; ">3000</span><span style="color: #000000; ">)<br />(c</span><span style="color: #000000; ">/</span><span style="color: #000000; ">DELETE&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://example.com</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />(c</span><span style="color: #000000; ">/</span><span style="color: #000000; ">POST&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">http://example.com</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;:body&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">hello&nbsp;world</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;:auth&nbsp;{:type&nbsp;:basic&nbsp;:user&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">admin</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;:password&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">admin</span><span style="color: #000000; ">"</span><span style="color: #000000; ">})</span></div><br />请注意，这些方法都是异步调用的，你需要通过await来等待调用完成，或者通过done?来判断调用是否完成。<br />http.async.client有个比较重要的特性就是对Http Chunked编码的支持，分别通过LazySeq和callback的方式支持，首先看将Http chunked变成一个lazy seq:<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(with</span><span style="color: #000000; ">-</span><span style="color: #000000; ">open&nbsp;[client&nbsp;(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">create</span><span style="color: #000000; ">-</span><span style="color: #000000; ">client)]&nbsp;;&nbsp;Create&nbsp;client<br />&nbsp;&nbsp;(let&nbsp;[resp&nbsp;(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">stream</span><span style="color: #000000; ">-</span><span style="color: #000000; ">seq&nbsp;client&nbsp;:get&nbsp;url)]<br />&nbsp;&nbsp;&nbsp;&nbsp;(doseq&nbsp;[s&nbsp;(s</span><span style="color: #000000; ">/</span><span style="color: #000000; ">string&nbsp;resp)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(println&nbsp;s))))</span></div><br />这里非常关键的一点是stream-seq返回的chunk序列，每取一个就少一个（通过first函数），也就是说每次调用first取到的chunk都不一样，是顺序递增，不可重复获取的。<br /><br />通过callback方式处理：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(with</span><span style="color: #000000; ">-</span><span style="color: #000000; ">open&nbsp;[client&nbsp;(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">create</span><span style="color: #000000; ">-</span><span style="color: #000000; ">client)]&nbsp;;&nbsp;Create&nbsp;client<br />&nbsp;&nbsp;(let&nbsp;[parts&nbsp;(ref&nbsp;#{})<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resp&nbsp;(client</span><span style="color: #000000; ">/</span><span style="color: #000000; ">request</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stream&nbsp;client&nbsp;:get&nbsp;url<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[state&nbsp;body]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(dosync&nbsp;(alter&nbsp;parts&nbsp;conj&nbsp;(string&nbsp;body)))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[body&nbsp;:</span><span style="color: #0000FF; ">continue</span><span style="color: #000000; ">]))]<br />&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;</span><span style="color: #0000FF; ">do</span><span style="color: #000000; ">&nbsp;something&nbsp;to&nbsp;@parts<br />&nbsp;&nbsp;&nbsp;&nbsp;))</span></div>自己传入一个callback函数接收chunk，比如这里用一个ref累积。<br /><br />http.async.client的详细文档看这里：<a href="http://neotyk.github.com/http.async.client/docs.html">http://neotyk.github.com/http.async.client/docs.html</a><br /><br />最后，有兴趣还可以看下<a href="https://github.com/ztellman/aleph">aleph</a>这个异步通讯的框架，它支持Http协议，也提供了http server和client的实现。不过它的API就没有那么简单明了，它的模型是类似go语言里利用channel做异步通讯的模型，http只是它的一个模块罢了，这是另一个话题了。<br /><br />转载请注明出处：<a id="Editor_Edit_hlEntryLink" title="view: Clojure世界：Http Client" href="../archive/2012/02/13/369890.html" target="_blank">http://www.blogjava.net/killme2008/archive/2012/02/13/369890.html</a><img src ="http://www.blogjava.net/killme2008/aggbug/369890.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> 2012-02-13 18:57 <a href="http://www.blogjava.net/killme2008/archive/2012/02/13/369890.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界：日志管理——clojure.tools.logging</title><link>http://www.blogjava.net/killme2008/archive/2012/02/12/369822.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 12 Feb 2012 12:53:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/02/12/369822.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/369822.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/02/12/369822.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/369822.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/369822.html</trackback:ping><description><![CDATA[<br />&nbsp;&nbsp;&nbsp; 处理日志是任何一个产品级的程序都需要仔细处理的模块。在Java中，我们经常使用的是log4j就是一个日志框架。在clojure里，同样有一套日志框架&#8212;&#8212;clojure.tools.logging，它不仅提供了常用的日志输出功能，还屏蔽了Java各种日志框架之间的差异，如slf4j,commons-logging,log4j,java.util.logging等，让你可以透明地使用这些框架来处理日志。<br /><br />名称：clojure.tools.logging<br />主页：<a href="https://github.com/clojure/tools.logging">https://github.com/clojure/tools.logging</a><br />依赖：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">[org.clojure/tools.logging&nbsp;"0.2.3"]<br /><br /></span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">dependency</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">groupId</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; ">org.clojure</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">groupId</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">artifactId</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; ">tools.logging</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">artifactId</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br />&nbsp;&nbsp;</span><span style="color: #0000FF; ">&lt;</span><span style="color: #800000; ">version</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; ">0.2.3</span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">version</span><span style="color: #0000FF; ">&gt;</span><span style="color: #000000; "><br /></span><span style="color: #0000FF; ">&lt;/</span><span style="color: #800000; ">dependency</span><span style="color: #0000FF; ">&gt;</span></div><br />使用：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(ns&nbsp;example.core<br />&nbsp;&nbsp;(:use&nbsp;[clojure.tools.logging&nbsp;:only&nbsp;(info&nbsp;error)]))<br /><br />(defn&nbsp;divide&nbsp;[x&nbsp;y]<br />&nbsp;&nbsp;(try<br />&nbsp;&nbsp;&nbsp;&nbsp;(info&nbsp;"dividing"&nbsp;x&nbsp;"by"&nbsp;y)<br />&nbsp;&nbsp;&nbsp;&nbsp;(/&nbsp;x&nbsp;y)<br />&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;ex&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(error&nbsp;ex&nbsp;"There&nbsp;was&nbsp;an&nbsp;error&nbsp;in&nbsp;calculation"))))<br /></span></div><br />常用宏和方法：<br />1.除了上面例子的info和error宏，还可以包括warn,trace,debug,fatal等常用宏，分别对应相应的日志级别。这些方法会自动判断当前logger的级别是否有效，有效的前提下才会输出日志。也就是说在Java里，你经常需要这样：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(logger.isDebugEnabled())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(x&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;plus&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;y&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;is&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;(x&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;y));<br />}</span></div>在使用 tools.logging的时候是不需要的，因为这些宏帮你做了这个判断。另外，我们在使用log4j的时候需要指定log的namespace，在tools.logging里不需要，默认会取当前的namespace也就是*ns*。<br />最后，info还有个infof的方法，用于输出格式化日志：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(infof&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">%s&nbsp;is&nbsp;%d&nbsp;years&nbsp;old</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">kid</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">)</span></div>日志输出：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">2012</span><span style="color: #000000; ">-</span><span style="color: #000000; ">02</span><span style="color: #000000; ">-</span><span style="color: #000000; ">12</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">20</span><span style="color: #000000; ">:</span><span style="color: #000000; ">23</span><span style="color: #000000; ">:</span><span style="color: #000000; ">07</span><span style="color: #000000; ">,</span><span style="color: #000000; ">394</span><span style="color: #000000; ">&nbsp;INFO&nbsp;&nbsp;log:&nbsp;kid&nbsp;is&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">&nbsp;years&nbsp;old</span></div>其他方法也有类似的如warnf,debugf等。<br />2.spy宏，同时输出表达式的form和结果，例如<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">（spy&nbsp;(</span><span style="color: #000000; ">+</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">))</span></div>输出日志<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">2012</span><span style="color: #000000; ">-</span><span style="color: #000000; ">02</span><span style="color: #000000; ">-</span><span style="color: #000000; ">12</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">20</span><span style="color: #000000; ">:</span><span style="color: #000000; ">11</span><span style="color: #000000; ">:</span><span style="color: #000000; ">47</span><span style="color: #000000; ">,</span><span style="color: #000000; ">415</span><span style="color: #000000; ">&nbsp;DEBUG&nbsp;log:&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; ">2</span><span style="color: #000000; ">)<br /></span><span style="color: #000000; ">=&gt;</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">3</span></div><br />3.with-logs宏可以在将*out*和*err*流重定向到日志的情况下求值表达式，例如：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(with</span><span style="color: #000000; ">-</span><span style="color: #000000; ">logs&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">ns</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;(prn&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">hello&nbsp;world</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-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">2012</span><span style="color: #000000; ">-</span><span style="color: #000000; ">02</span><span style="color: #000000; ">-</span><span style="color: #000000; ">12</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">20</span><span style="color: #000000; ">:</span><span style="color: #000000; ">17</span><span style="color: #000000; ">:</span><span style="color: #000000; ">32</span><span style="color: #000000; ">,</span><span style="color: #000000; ">592</span><span style="color: #000000; ">&nbsp;INFO&nbsp;&nbsp;log:&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">hello&nbsp;world</span><span style="color: #000000; ">"</span></div>with-logs需要明确指定log-ns，默认out的输出级别是info，而err的级别是error，可以指定输出级别(with-logs [*ns* :info :error] ......)<br /><br />4.事务中（dosync中）的日志输出，tools.logging做了特殊处理，默认情况下当且仅当事务成功提交的时候并且日志级别是warn或者info会通过agent异步写入日志。tools.logging定义了一个全局的agent&#8212;&#8212;*logging-agent*。当判断当前是在事务中调用log宏，并且日志级别在集合*tx-agent-levels*内，就会在事务提交成功的时候将日志发送给*logging-agent*异步处理。可以通过*tx-agent-levels*改变使用agent输出日志的级别范围，默认是#{:info :warn}。还可以通过改变*force*变量来强制使用direct或者agent的方式输出日志,*force*可以为:agent或者:direct。<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(binding&nbsp;[</span><span style="color: #000000; ">*</span><span style="color: #000000; ">force</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;:agent]<br />&nbsp;&nbsp;(log&nbsp;:info&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">hello&nbsp;world</span><span style="color: #000000; ">"</span><span style="color: #000000; ">))</span></div>这里特别使用了log宏，需要明确指定日志级别为info。<br /><br />5.默认日志框架的是从classpath查找的，查找的顺序是sl4j,commons-logging,log4j,java.util.logging，找到哪个可用就用哪个。如果你的classpath里存在多个日志框架，如同时存在sl4j和commons-logging，那么如果你希望强制使用commons-logging，可以通过改变*logger-factory*变量来使用：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(ns&nbsp;example<br />&nbsp;&nbsp;(:use&nbsp;[clojure.tools.logging.impl&nbsp;:only&nbsp;[cl</span><span style="color: #000000; ">-</span><span style="color: #000000; ">factory]]))<br />(binding&nbsp;[</span><span style="color: #000000; ">*</span><span style="color: #000000; ">logger</span><span style="color: #000000; ">-</span><span style="color: #000000; ">factory</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;(cl</span><span style="color: #000000; ">-</span><span style="color: #000000; ">factory)]<br />&nbsp;&nbsp;(info&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">hello&nbsp;world</span><span style="color: #000000; ">"</span><span style="color: #000000; ">))<br /><br /></span></div>*logger-factory*是dynamic变量，可以通过binding改变（前面提到的*force*等变量也一样），如果不希望每次都用binding，而是全局改变，则需要特殊处理：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(alter</span><span style="color: #000000; ">-</span><span style="color: #000000; ">var</span><span style="color: #000000; ">-</span><span style="color: #000000; ">root&nbsp;(var&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">logger</span><span style="color: #000000; ">-</span><span style="color: #000000; ">factory</span><span style="color: #000000; ">*</span><span style="color: #000000; ">)&nbsp;(constantly&nbsp;(cl</span><span style="color: #000000; ">-</span><span style="color: #000000; ">factory))) <br /></span></div>其他logger factory还包括slf4j-factory,log4j-factory,jul-factory。<br /><br />6.每个日志框架的配置跟使用java没有什么两样，比如你用log4j，就需要在classpath下放置一个log4j.properties等。如果你希望用编程的方式配置，可以使用<a href="http://github.com/malcolmsparks/clj-logging-config">clj-logging-config</a>。<br /><br />转载请注明出处：<a id="Editor_Edit_hlEntryLink" title="view: Clojure世界：日志管理&#8212;&#8212;clojure.tools.logging" href="../archive/2012/02/12/369822.html" target="_blank">http://www.blogjava.net/killme2008/archive/2012/02/12/369822.html</a><img src ="http://www.blogjava.net/killme2008/aggbug/369822.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> 2012-02-12 20:53 <a href="http://www.blogjava.net/killme2008/archive/2012/02/12/369822.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure世界： STM的统计</title><link>http://www.blogjava.net/killme2008/archive/2012/02/09/369694.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 09 Feb 2012 12:55:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/02/09/369694.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/369694.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/02/09/369694.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/369694.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/369694.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 年前一篇blog提过，写了一个stm-profiler用于统计clojure STM的运行状况，放在了github上：<br />
<a href="https://github.com/killme2008/stm-profiler">https://github.com/killme2008/stm-profiler</a><br />
<br />
&nbsp;&nbsp; STM的事务在遇到写冲突（多个事务写同一个ref的时候）就会回滚事务并重试，通过stm-profiler你可以查看事务的重试次数，重试原因，以及每个reference的使用情况。使用很简单，在lein的project.clj引用stm-profiler:<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">[stm-profiler&nbsp;"1.0.2-SNAPSHOT"]</span></div>
<br />
注意，目前stm profiler仅支持clojure 1.3。<br />
<br />
我们写一个简单例子：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">(use&nbsp;'stm)<br />
(def&nbsp;a&nbsp;(ref&nbsp;1))<br />
(def&nbsp;b&nbsp;(ref&nbsp;2))<br />
<br />
(dotimes&nbsp;[_&nbsp;100]&nbsp;(future&nbsp;(dosync&nbsp;(alter&nbsp;a&nbsp;+&nbsp;1)&nbsp;(alter&nbsp;b&nbsp;-&nbsp;1))))<br />
(Thread/sleep&nbsp;1000)<br />
(prn&nbsp;@a)<br />
(prn&nbsp;@b)<br />
(Thread/sleep&nbsp;1000)<br />
(prn&nbsp;"stm&nbsp;statistics"&nbsp;(stm-stats))<br />
(prn&nbsp;"reference&nbsp;a&nbsp;statistics"&nbsp;(ref-stats&nbsp;a))<br />
(prn&nbsp;"reference&nbsp;b&nbsp;statistics"&nbsp;(ref-stats&nbsp;b))<br />
</span></div>
<br />
定义了两个ref：a和b，然后用future启动100个线程并发地发起同一个事务操作，对a加一，对b减一。最后打印a和b的值，使用stm-stats函数获取stm的统计信息并打印，使用ref-stats获取a和b两个reference的统计信息并打印。<br />
<br />
运行这个例子，在启动的时候会有些警告信息，忽略即可（主要是因为stm profiler重新定义了一些跟STM相关的函数和宏，如dosync等，但是仅仅是添加了统计功能，并没有修改他们原本的功能）。<br />
<br />
在我机器上的一次输出：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">101<br />
-98<br />
"stm&nbsp;statistics"&nbsp;{"(alter&nbsp;a&nbsp;+&nbsp;1)(alter&nbsp;b&nbsp;-&nbsp;1)"&nbsp;{:not-running&nbsp;11,&nbsp;:average-retry&nbsp;5,&nbsp;:total-cost&nbsp;1233,&nbsp;:get-fault&nbsp;44,&nbsp;:barge-fail&nbsp;224,&nbsp;:change-committed&nbsp;227,&nbsp;:total-times&nbsp;100,&nbsp;:average-cost&nbsp;12}}<br />
"reference&nbsp;a&nbsp;statistics"&nbsp;{"(alter&nbsp;a&nbsp;+&nbsp;1)(alter&nbsp;b&nbsp;-&nbsp;1)"&nbsp;{:alter&nbsp;609,&nbsp;:get-fault&nbsp;44,&nbsp;:barge-fail&nbsp;224,&nbsp;:change-committed&nbsp;227}}<br />
"reference&nbsp;b&nbsp;statistics"&nbsp;{"(alter&nbsp;a&nbsp;+&nbsp;1)(alter&nbsp;b&nbsp;-&nbsp;1)"&nbsp;{:alter&nbsp;114,&nbsp;:not-running&nbsp;11}}</span></div>
<br />
a和b的结果都没问题。重点看打印的统计信息，(stm-stats)的输出结果是：<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000; ">{"(alter&nbsp;a&nbsp;+&nbsp;1)(alter&nbsp;b&nbsp;-&nbsp;1)"&nbsp;{:not-running&nbsp;11,&nbsp;:average-retry&nbsp;5,&nbsp;:total-cost&nbsp;1233,&nbsp;:get-fault&nbsp;44,&nbsp;:barge-fail&nbsp;224,&nbsp;:change-committed&nbsp;227,&nbsp;:total-times&nbsp;100,&nbsp;:average-cost&nbsp;12}}</span></div>
<br />
这个结果是一个map,key是事务的form，而value就是该form的统计信息，也是一个map，具体各项的含义如下：<br />
<table bgcolor="#C0C0C0" border="3" bordercolor="#000000" cellpadding="2" cellspacing="2" height="102" width="722">
     <tbody>
         <tr>
             <td> total-cost<br />
             </td>
             <td> 所有事务的总耗时<br />
             </td>
             <td> 100个事务耗时1233毫秒<br />
             </td>
         </tr>
         <tr>
             <td> total-times<br />
             </td>
             <td> 事务运行次数<br />
             </td>
             <td> 100次<br />
             </td>
         </tr>
         <tr>
             <td> average-cost<br />
             </td>
             <td> 平均每个事务耗时<br />
             </td>
             <td> 平均一个事务耗时12毫秒<br />
             </td>
         </tr>
         <tr>
             <td>average-retry<br />
             </td>
             <td>平均每个事务的重试次数</td>
             <td>&nbsp;平均每个事务重试了5次才成功</td>
         </tr>
         <tr>
             <td>not-running</td>
             <td>&nbsp;当前事务不处于running状态，可能是被其他事务打断（barge)，需要重试</td>
             <td>&nbsp;因为not-running的原因重试了11次</td>
         </tr>
         <tr>
             <td>get-fault<br />
             </td>
             <td>&nbsp;读取ref值的时候没有找到read point之前的值，被认为是一次读错误，需要重试<br />
             </td>
             <td>&nbsp;因为读ref错误重试了44次<br />
             </td>
         </tr>
         <tr>
             <td>barge-fail</td>
             <td>&nbsp;打断其他事务失败次数，需要重试</td>
             <td>&nbsp;尝试打断其他事务失败而重试了224次</td>
         </tr>
         <tr>
             <td>change-committed</td>
             <td>&nbsp;在本事务read point之后有ref值获得提交，则需要重试<br />
             </td>
             <td>&nbsp;因为ref值被其他事务提交而重试了227次</td>
         </tr>
     </tbody>
</table>
<br />
&nbsp;&nbsp;&nbsp; 从输出结果来看，这么简单的一个事务操作，每次事务要成功平均都需要经过5次的重试，最大的原因是因为ref的值在事务中被其他事务更改了，或者尝试打断其他正在运行的事务失败而重试。关于clojure STM的具体原理推荐看这篇文章《<a href="http://java.ociweb.com/mark/stm/article.html#barge">Software transactional memory</a>》。STM不是完美的，事务重试和保存每个reference的历史版本的代价都不低。<br /><br />&nbsp;&nbsp;&nbsp; 再看<span style="color: #000000;">(ref-stats&nbsp;a)的输出：<br /></span><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">{"(alter&nbsp;a&nbsp;+&nbsp;1)(alter&nbsp;b&nbsp;-&nbsp;1)"&nbsp;{:alter&nbsp;609,&nbsp;:get-fault&nbsp;44,&nbsp;:barge-fail&nbsp;224,&nbsp;:change-committed&nbsp;227}}</span></div>&nbsp;&nbsp;&nbsp; 可以看到a在所有事务中的统计信息，返回的结果同样是个map，key是使用了a的事务，value是具体的统计信息。各项的含义类似上表，不过这里精确到了具体的reference。其中alter项是指对a调用alter函数了609次。ref-stats会输出所有在事务中调用了a的函数的调用次数。<br /><br />&nbsp;&nbsp;&nbsp; 通过stm profiler你可以分析具体每个事务的执行状况，甚至每个reference的运行状况，查找热点事务和热点reference等。stm-profiler还不完善，目前还不支持1.2（1.4测试是可以的）。希望有兴趣的朋友加入进来一起完善。<br /><br />转载请注明出处：<a id="Editor_Edit_hlEntryLink" title="view: Clojure世界： STM的统计" href="../archive/2012/02/09/369694.html" target="_blank">http://www.blogjava.net/killme2008/archive/2012/02/09/369694.html</a><img src ="http://www.blogjava.net/killme2008/aggbug/369694.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> 2012-02-09 20:55 <a href="http://www.blogjava.net/killme2008/archive/2012/02/09/369694.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第二次cn-clojure线下聚会</title><link>http://www.blogjava.net/killme2008/archive/2012/02/09/369655.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 09 Feb 2012 04:37:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2012/02/09/369655.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/369655.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2012/02/09/369655.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/369655.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/369655.html</trackback:ping><description><![CDATA[<br />&nbsp;&nbsp;&nbsp; 去年（我靠，已经是去年了）首次在上海组织了第一次cn-clojure的线下聚会，详细可以看<a href="http://www.blogjava.net/killme2008/archive/2011/08/09/356106.html">这篇blog</a>。今年，我们将在北京举行第二次cn-clojure的聚会，时间大概在2月底或者3月初，具体地点待定，欢迎任何对clojure语言或者Lisp语言感兴趣的朋友参加，如果有想分享的技术topic更好 :D。<br /><br />&nbsp;&nbsp;&nbsp; 如果你要参加，请参加下面的报名调查，填写真实的姓名和邮箱。如果有想分享的topic，可以填写调查或者直接邮件给我。<br />&nbsp;&nbsp;&nbsp; 报名链接：<a href="http://www.diaochapai.com/survey584561">http://www.diaochapai.com/survey584561</a><br /><br />&nbsp;&nbsp;&nbsp; 我们将在议程、时间和地点确定后发邮件给报名的朋友，确认参会的具体时间和地点。<br />&nbsp;&nbsp;&nbsp; 邮件列表：<a href="http://groups.google.com/group/cn-clojure">http://groups.google.com/group/cn-clojure</a><img src ="http://www.blogjava.net/killme2008/aggbug/369655.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> 2012-02-09 12:37 <a href="http://www.blogjava.net/killme2008/archive/2012/02/09/369655.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Storm源码浅析之topology的提交</title><link>http://www.blogjava.net/killme2008/archive/2011/12/01/364112.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 01 Dec 2011 13:48:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/12/01/364112.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/364112.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/12/01/364112.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/364112.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/364112.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 原文：<a href="http://www.blogjava.net/killme2008/archive/2011/11/17/364112.html">http://www.blogjava.net/killme2008/archive/2011/11/17/364112.html</a><br />&nbsp;&nbsp;&nbsp; 作者：dennis (killme2008@gmail.com)<br />&nbsp;&nbsp;&nbsp; 转载请注明出处。<br /><br />&nbsp;&nbsp;&nbsp; 最近一直在读twitter开源的这个分布式流计算框架&#8212;&#8212;storm的源码，还是有必要记录下一些比较有意思的地方。我按照storm的主要概念进行组织，并且只分析我关注的东西，因此称之为浅析。&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br /><br />一、介绍<br />&nbsp;&nbsp;&nbsp; Storm的开发语言主要是Java和Clojure，其中Java定义骨架，而Clojure编写核心逻辑。源码统计结果：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">180</span><span style="color: #000000; ">&nbsp;text&nbsp;files.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">177</span><span style="color: #000000; ">&nbsp;unique&nbsp;files.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">7</span><span style="color: #000000; ">&nbsp;files&nbsp;ignored.<br /><br />http:</span><span style="color: #008000; ">//</span><span style="color: #008000; ">cloc.sourceforge.net&nbsp;v&nbsp;1.55&nbsp;&nbsp;T=1.0&nbsp;s&nbsp;(171.0&nbsp;files/s,&nbsp;46869.0&nbsp;lines/s)</span><span style="color: #008000; "><br /></span><span style="color: #000000; ">-------------------------------------------------------------------------------</span><span style="color: #000000; "><br />Language&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;files&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;blank&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;comment&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;code<br /></span><span style="color: #000000; ">-------------------------------------------------------------------------------</span><span style="color: #000000; "><br />Java&nbsp;&nbsp;&nbsp;&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: #000000; ">125</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">5010</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">2414</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">25661</span><span style="color: #000000; "><br />Lisp&nbsp;&nbsp;&nbsp;&nbsp;&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: #000000; ">33</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">732</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">283</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">4871</span><span style="color: #000000; "><br />Python&nbsp;&nbsp;&nbsp;&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: #000000; ">7</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">742</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">433</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">4675</span><span style="color: #000000; "><br />CSS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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: #000000; ">1</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">12</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">45</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">1837</span><span style="color: #000000; "><br /><a title="" href="http://www.ruby-lang.org">ruby</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;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">22</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">104</span><span style="color: #000000; "><br />Bourne&nbsp;Shell&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: #000000; ">1</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">6</span><span style="color: #000000; "><br />Javascript&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: #000000; ">2</span><span style="color: #000000; ">&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; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">15</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">6</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">-------------------------------------------------------------------------------</span><span style="color: #000000; "><br />SUM:&nbsp;&nbsp;&nbsp;&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: #000000; ">171</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">6519</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">3190</span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">37160</span><span style="color: #000000; "><br /></span><span style="color: #000000; ">-------------------------------------------------------------------------------</span></div><br />&nbsp; &nbsp; Java代码25000多行，而Clojure(Lisp)只有4871行，说语言不重要再次证明是扯淡。<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />二、Topology和Nimbus &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; Topology是storm的核心理念，将spout和bolt组织成一个topology，运行在storm集群里，完成实时分析和计算的任务。这里我主要想介绍下topology部署到storm集群的大概过程。提交一个topology任务到Storm集群是通过StormSubmitter.submitTopology方法提交：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">StormSubmitter.submitTopology(name,&nbsp;conf,&nbsp;builder.createTopology());</span></div>&nbsp;&nbsp;&nbsp; 我们将topology打成jar包后，利用bin/storm这个python脚本，执行如下命令：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">bin</span><span style="color: #000000; ">/</span><span style="color: #000000; ">storm&nbsp;jar&nbsp;xxxx.jar&nbsp;com.taobao.MyTopology&nbsp;args</span></div>&nbsp;&nbsp;&nbsp; 将jar包提交给storm集群。storm脚本会启动JVM执行Topology的main方法，执行submitTopology的过程。而submitTopology会将jar文件上传到nimbus，上传是通过socket传输。在storm这个python脚本的jar方法里可以看到：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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;jar(jarfile,&nbsp;klass,&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">args):&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;exec_storm_class(&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;klass,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jvmtype</span><span style="color: #000000; ">=</span><span style="color: #800000; ">"</span><span style="color: #800000; ">-client</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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;extrajars</span><span style="color: #000000; ">=</span><span style="color: #000000; ">[jarfile,&nbsp;CONF_DIR,&nbsp;STORM_DIR&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">/bin</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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;args</span><span style="color: #000000; ">=</span><span style="color: #000000; ">args,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>prefix</strong></span><strong><span style="color: #000000; ">=</span><span style="color: #800000; ">"</span><span style="color: #800000; ">export&nbsp;STORM_JAR=</span><span style="color: #800000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;jarfile&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;</span><span style="color: #800000; ">"</span><span style="color: #800000; ">;</span><span style="color: #800000; ">"</span></strong><span style="color: #000000; "><strong>)</strong> <br /></span></div>&nbsp;&nbsp;&nbsp;&nbsp; 将jar文件的地址设置为环境变量STORM_JAR，这个环境变量在执行submitTopology的时候用到：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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; ">StormSubmitter.java&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #0000FF; ">private</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">static</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">void</span><span style="color: #000000; ">&nbsp;submitJar(Map&nbsp;conf)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">(submittedJar</span><span style="color: #000000; ">==</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOG.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Jar&nbsp;not&nbsp;uploaded&nbsp;to&nbsp;master&nbsp;yet.&nbsp;Submitting&nbsp;jar<img src="http://www.blogjava.net/Images/dot.gif" alt="" /></span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;localJar&nbsp;</span><span style="color: #000000; ">=</span><strong><span style="color: #000000; ">&nbsp;System.getenv(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">STORM_JAR</span><span style="color: #000000; ">"</span></strong><span style="color: #000000; "><strong>)</strong>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;submittedJar&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;submitJar(conf,&nbsp;localJar);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LOG.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Jar&nbsp;already&nbsp;uploaded&nbsp;to&nbsp;master.&nbsp;Not&nbsp;submitting&nbsp;jar.</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>&nbsp;&nbsp;&nbsp; 通过环境变量找到jar包的地址，然后上传。利用环境变量传参是个小技巧。<br /><br />&nbsp;&nbsp;&nbsp; 其次，nimbus在接收到jar文件后，存放到数据目录的inbox目录，<strong>nimbus数据目录的结构</strong>：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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; ">nimbus<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">inbox<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormjar</span><span style="color: #000000; ">-</span><span style="color: #000000; ">57f1d694</span><span style="color: #000000; ">-</span><span style="color: #000000; ">2865</span><span style="color: #000000; ">-</span><span style="color: #000000; ">4b3b</span><span style="color: #000000; ">-</span><span style="color: #000000; ">8a7c</span><span style="color: #000000; ">-</span><span style="color: #000000; ">99104fc0aea3.jar<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormjar</span><span style="color: #000000; ">-</span><span style="color: #000000; ">76b4e316</span><span style="color: #000000; ">-</span><span style="color: #000000; ">b430</span><span style="color: #000000; ">-</span><span style="color: #000000; ">4215</span><span style="color: #000000; ">-</span><span style="color: #000000; ">9e26</span><span style="color: #000000; ">-</span><span style="color: #000000; ">4f33ba4ee520.jar<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormdist<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">storm</span><span style="color: #000000; ">-</span><span style="color: #000000; ">id<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormjar.jar<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormconf.ser<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">stormcode.ser</span></div>&nbsp;&nbsp;&nbsp;&nbsp; 其中inbox用于存放提交的jar文件，每个jar文件都重命名为stormjar加上一个32位的UUID。而stormdist存放的是启动topology后生成的文件，每个topology都分配一个唯一的id，ID的规则是&#8220;name-计数-时间戳&#8221;。启动后的topology的jar文件名命名为storm.jar ,而它的配置经过java序列化后存放在stormconf.ser文件，而stormcode.ser是将topology本身序列化后存放的文件。<strong>这些文件在部署的时候，supervisor会从这个目录下载这些文件，然后在supervisor本地执行这些代码。</strong><br />&nbsp;&nbsp;&nbsp; 进入重点，topology任务的分配过程(zookeeper路径说明忽略root):<br />1.在zookeeper上创建/taskheartbeats/{storm id} 路径，用于任务的心跳检测。storm对zookeeper的一个重要应用就是利用zk的临时节点做存活检测。task将定时刷新节点的时间戳，然后nimbus会检测这个时间戳是否超过timeout设置。<br />2.从topology中获取bolts,spouts设置的并行数目以及全局配置的最大并行数，然后产生task id列表，如[1 2 3 4]<br />3.在zookeeper上创建/tasks/{strom id}/{task id}路径，并存储task信息<br />4.开始分配任务（内部称为assignment)， 具体步骤：<br />&nbsp;(1)从zk上获得已有的assignment(新的toplogy当然没有了）<br />&nbsp;(2)查找所有可用的slot，所谓slot就是可用的worker，在所有supervisor上配置的多个worker的端口。<br />&nbsp;(3)将任务均匀地分配给可用的worker，这里有两种情况：<br />&nbsp;(a)task数目比worker多，例如task是[1 2 3 4],可用的slot只有[host1:port1 host2:port1]，那么最终是这样分配<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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; ">1</span><span style="color: #000000; ">:&nbsp;[host1:port1]&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;:&nbsp;[host2:port1]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000; ">3</span><span style="color: #000000; ">&nbsp;:&nbsp;[host1:port1]&nbsp;</span><span style="color: #000000; ">4</span><span style="color: #000000; ">&nbsp;:&nbsp;[host2:port1]}</span></div>，可以看到任务平均地分配在两个worker上。<br />(b)如果task数目比worker少，例如task是[1 2]，而worker有[host1:port1 host1:port2 host2:port1 host2:port2]，那么首先会将woker排序，<strong>将不同host间隔排列</strong>，保证task不会全部分配到同一个worker上，也就是将worker排列成<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">[host1:port1&nbsp;host2:port1&nbsp;host1:port2&nbsp;host2:port2]</span></div>，然后分配任务为<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<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; ">1</span><span style="color: #000000; ">:&nbsp;host1:port1&nbsp;,&nbsp;</span><span style="color: #000000; ">2</span><span style="color: #000000; ">&nbsp;:&nbsp;host2:port2}</span></div><br />(4)记录启动时间<br />(5)判断现有的assignment是否跟重新分配的assignment相同，如果相同，不需要变更，否则更新assignment到zookeeper的/assignments/{storm id}上。<br />5.启动topology，所谓启动，只是将zookeeper上/storms/{storm id}对应的数据里的active设置为true。<br />6.nimbus会检查task的心跳，如果发现task心跳超过超时时间，那么会重新跳到第4步做re-assignment。<br /><img src ="http://www.blogjava.net/killme2008/aggbug/364112.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> 2011-12-01 21:48 <a href="http://www.blogjava.net/killme2008/archive/2011/12/01/364112.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>storm集群的监控</title><link>http://www.blogjava.net/killme2008/archive/2011/12/01/365329.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 01 Dec 2011 13:02:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/12/01/365329.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/365329.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/12/01/365329.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/365329.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/365329.html</trackback:ping><description><![CDATA[<br />&nbsp;&nbsp;&nbsp; 所谓兵马未动，粮草先行，准备将<a href="https://github.com/nathanmarz/storm/wiki">storm</a>用在某个项目中做实时数据分析。无论任何系统，一定要有监控系统并存，当故障发生的时候你能第一个知道，而不是让别人告诉你，那处理故障就很被动了。<br /><br />&nbsp;&nbsp;&nbsp; 因此我写了这么个项目，取名叫storm-monitor，放在了github上<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://github.com/killme2008/storm-monitor">https://github.com/killme2008/storm-monitor</a><br /><br />&nbsp;&nbsp;&nbsp; 主要功能如下：<br />1.监控supervisor数目是否正确，当supervisor挂掉的时候会发送警告。<br />2.监控nimbus是否正常运行，monitor会尝试连接nimbus，如果连接失败就认为nimbus挂掉。<br />3.监控topology是否正常运行，包括它是否正常部署，是否有运行中的任务。<br /><br />&nbsp;&nbsp;&nbsp; 当故障发生的时候通过alarm方法警告用户，开放出去的只是简单地打日志。因为每个公司的告警接口不一样，所以你需要自己扩展，修改alarm.clj即可。我们这儿就支持旺旺告警和手机短信告警。<br /><br />&nbsp;&nbsp;&nbsp; 基本的原理很简单，对supervisor和topology的监控是通过zookeeper来间接地监控，通过定期查看path是否存在。对nimbus的监控是每次起一个短连接连上去，连不上去即认为挂掉。<br /><br />&nbsp;&nbsp;&nbsp; 整个项目也是用clojure写。你的机器需要安装<a href="https://github.com/technomancy/leiningen">lein</a>和<a href="https://github.com/kumarshantanu/lein-exec">exec</a>插件，然后将你的storm.yaml拷贝到conf目录下，编辑monitor.yaml设定监控参数如检查间隔等，最后启动start.sh脚本即可。默认日志输出在logs/monitor.log。<br /><img src ="http://www.blogjava.net/killme2008/aggbug/365329.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> 2011-12-01 21:02 <a href="http://www.blogjava.net/killme2008/archive/2011/12/01/365329.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>clj-xmemcached:  memcached client for clojure</title><link>http://www.blogjava.net/killme2008/archive/2011/10/30/362315.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 30 Oct 2011 05:03:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/10/30/362315.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/362315.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/10/30/362315.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/362315.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/362315.html</trackback:ping><description><![CDATA[<div class="wikistyle"><h1><a href="https://github.com/killme2008/clj-xmemcached">clj-xmemcached</a></h1>

<p>&nbsp;&nbsp;&nbsp; <a href="https://github.com/killme2008/clj-xmemcached">Clj-xmemcached</a> is an opensource memcached client for clojure wrapping <a href="http://code.google.com/p/xmemcached/">xmemcached</a>. <a href="http://code.google.com/p/xmemcached/">Xmemcached</a> is an opensource high performance memcached client for java.</p>

<h2>Leiningen Usage</h2>

<p>To include clj-xmemcached,add:</p>

<pre><code>     [clj-xmemcached "0.1.1"]
</code></pre>

<p>to your project.clj.</p>

<h2>Usage</h2>

<h3>Create a client<code></code></h3><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(use&nbsp;[clj</span><span style="color: #000000; ">-</span><span style="color: #000000; ">xmemcached.core])<br />(def&nbsp;client&nbsp;(xmemcached&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">host:port</span><span style="color: #000000; ">"</span><span style="color: #000000; ">))<br />(def&nbsp;client&nbsp;(xmemcached&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">host1:port1&nbsp;host2:port2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;:protocol&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">binary</span><span style="color: #000000; ">"</span><span style="color: #000000; ">))</span></div>



<p>Then we create a memcached client using binary protocol to talk with memcached servers host1:port1 and host2:port2.
Valid options including:</p>

<pre><code>  :name       Client's name
  :protocol  Protocol to talk with memcached,a string value in text,binary or kestrel,default is text protocol.
  :hash          Hash algorithm,a string value in consistent or standard,default is standard hash.
  :timeout    Operation timeout in milliseconds,default is five seconds.
  :pool          Connection pool size,default is one.
</code></pre>

<h3>Store items<code></code></h3><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(xset&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">dennis</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />(xset&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">dennis</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">100</span><span style="color: #000000; ">)<br />(xappend&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;zhuang</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />(xprepend&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">hello,</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)</span></div><br />



<p>The value 100 is the expire time for the item in seconds.Store 
functions include xset,xadd,xreplace,xappend and xprepend.Please use doc
 to print documentation for these functions.</p>

<h3>Get items</h3>

<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(xget&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />(xget&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key3</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />(xgets&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)</span><code>
</code></div>

<p>xgets returns a value including a cas value,for example:</p>

<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;{:value&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">hello,dennis&nbsp;zhuang</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;:</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">&nbsp;net.rubyeye.xmemcached.GetsResponse,&nbsp;:cas&nbsp;</span><span style="color: #000000; ">396</span><span style="color: #000000; ">}</span><code>
</code></div>

<p>And bulk get returns a HashMap contains existent items.</p>

<h3>Increase/Decrease numbers<code></code></h3><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(xincr&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">num</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">)<br />(xdecr&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">num</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">)<br />(xincr&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">num</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; ">0</span><span style="color: #000000; ">)</span></div><br />



<p>Above codes try to increase/decrease a number in memcached with key "num",and if the item is not exists,then set it to zero.</p>

<h3>Delete items</h3>

<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(xdelete&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">num</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)</span><code>
</code></div>

<h3>Compare and set</h3>

<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(xcas&nbsp;client&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">key</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;inc)</span><code>
</code></div>

<p>We use inc function to increase the current value in memcached and try to compare and set it at most Integer.MAX_VALUE times.
xcas can be called as:<code><br /></code></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;(xcas&nbsp;client&nbsp;key&nbsp;cas</span><span style="color: #000000; ">-</span><span style="color: #000000; ">fn&nbsp;max</span><span style="color: #000000; ">-</span><span style="color: #000000; ">times)</span></div><p><code>
</code></p>



<p>The cas-fn is a function to return a new value,set the new value to </p>

<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(cas</span><span style="color: #000000; ">-</span><span style="color: #000000; ">fn&nbsp;current</span><span style="color: #000000; ">-</span><span style="color: #000000; ">value)</span><code>
</code></div>

<h3>Shutdown</h3>

<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(xshutdown&nbsp;client)</span><code>
</code></div>

<h3>Flush</h3>

<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(xflush&nbsp;client)<br />(xflush&nbsp;client&nbsp;(InetSocketAddress.&nbsp;host&nbsp;port))</span><code>
</code></div>

<h3>Statistics</h3>

<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">(xstats&nbsp;client)</span><code>
</code></div>

<h3>Example</h3>

<p>Please see the example code in <a href="https://github.com/killme2008/clj-xmemcached/blob/master/example/demo.clj">example/demo.clj</a></p>

<h2>License</h2>

<p>Copyright (C) 2011-2014 dennis zhuang[<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#105;&#108;&#108;&#109;&#101;&#50;&#48;&#48;&#56;&#64;&#103;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">killme2008@gmail.com</a>]</p>

<p>Distributed under the Eclipse Public License, the same as Clojure.</p></div><img src ="http://www.blogjava.net/killme2008/aggbug/362315.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> 2011-10-30 13:03 <a href="http://www.blogjava.net/killme2008/archive/2011/10/30/362315.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>记首次cn-clojure线下聚会</title><link>http://www.blogjava.net/killme2008/archive/2011/08/09/356106.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 09 Aug 2011 06:09:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/08/09/356106.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/356106.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/08/09/356106.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/356106.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/356106.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 没有耐心看经过的请直接拉到末尾看slide列表。<br /><br />&nbsp;&nbsp;&nbsp; 这个聚会是由江宏首先提议的，我参与协助。目的是让长三角地区对<a href="http://clojure.org">clojure语言</a>感兴趣，或者正在使用的朋友当面认识和交流一下。会议的组织过程一波三折，首先是会议地点本来定在了上海google办公室，但是后来google那边又说不让过去，我再联系了原来淘宝网的同事火狐，经过他的努力和帮助，最终将地点确定在了上海大众点评。要感谢大众点评网和火狐的帮助，不然这次活动估计就黄了。会议的日期选定也比较偶然，跟七夕撞在了一天，并且8月6号这天说台风&#8220;梅花&#8221;要在江浙一带登陆，上海要刮多少级多少级的大风，加上我和杭州的几个朋友过去要坐高铁，那心里就七上八下了，搞不好就要被&#8220;掩埋&#8221;了。我们还开玩笑说最好买火车中段车厢的票为妙。<br /><br />&nbsp;&nbsp;&nbsp; 8月6日一早，和同在淘宝的杨冬，加上两位做ROR的朋友一起出发，天气没有想象的糟糕，高铁一个小时就到了，转地铁到大众点评网大概也才中午12点左右。打了电话给火狐，一起吃了饭然后就直奔大众点评网。大众点评网的前台大厅装修也是非常熟悉的橙色，很意外周6有很多人，后来才知道是在搞招聘会和培训。这时候，江宏他们也从昆山赶到了，火狐帮我们定的会议室很大，足够容纳20号人左右。陆续有人达到，到约定的1点的时候，我记的是来了大概11还是12个人，还有几个朋友在路上，因此我们决定推迟到1点半再开始。最终来的人估计有15个以上，估计报名的都来了。<br /><br />&nbsp;&nbsp;&nbsp; 1点半正式开始，首先是我来讲《clojure概览》这个topic，主要是一个clojure语言的介绍。这个是我上周开始准备的，在去年《clojure的魅力》的基础上做了删减和增加，听取江宏的意见增加了示例和引子。上周也在我们的团队讲过一次。轻车熟路，也为了给后面的topic留出时间，我讲的比较快，大概40分钟就结束了。<br /><br />&nbsp;&nbsp;&nbsp; 接下来是孙宁（sunng87)讲《clojure开发的生命周期管理》，我对clojure的周边工具并不熟悉，趁机更好地了解了很多 clojure开发过程中用到的工具和资料，推荐对clojure开发感兴趣的朋友看下。尝试了下<a href="https://github.com/arthuredelstein/clooj">clooj</a>，比我预期的要好，遗憾的是还没有语法高亮，推荐初学clojure的朋友可以尝试下这个轻量级的IDE。目前最好的clojure IDE还是idea里的La Clojure插件。最后孙宁顺便广告了下<a href="https://github.com/sunng87/lein-control">lein-control</a>插件，这是孙宁构建的一个<a href="https://github.com/killme2008/clojure-control">clojure-control</a>的lein插件，他还贡献了一个类似python里<a href="http://docs.fabfile.org/en/1.2.0/api/core/context_managers.html">fabric</a>的clojure DSL实现，让clojure-control更易用。<br /><br />&nbsp;&nbsp;&nbsp; 接下来是江宏介绍他们开发<a href="https://trakrapp.com/">trakrapp.com</a>这个纯clojure实现的网站中使用的技术，以及遇到的问题和经验。这个网站基于<a href="https://github.com/weavejester/compojure">compojure</a>这个框架实现的，前端采用backbone.js，后端是MongoDB和postgresql，可以说都是非常&#8220;新潮&#8221;的技术。他在谈遇到问题的时候，提到clojure的stack trace又长又丑，这一点深有体会，clojure的异常堆栈包含了java和clojure的，整个调用链相对较长，非常不利于问题的排查，不知道后续clojure会不会对这一点做出改进。<br /><br />&nbsp;&nbsp;&nbsp; 接下来是林晴介绍他们一个用scala实现的类似domino的企业OA系统，不过他这个例子给我的感觉更多是发挥了mongodb的schema free的特点，没有体现出使用scala的好处来。我对scala的观点一直很明确，scala想做JVM上的c++，从个人角度不喜欢这种多范式的语言，并且语法不符合我的胃口，特别是类型系统这块特别复杂，我怕我在写scala的时候还要参考一本厚厚的reference，这不是我想要的。而clojure的核心就非常小，相对符合我的期望。<br /><br />&nbsp;&nbsp;&nbsp; 作为东道主的火狐介绍了<a href="http://www.dianping.com">大众点评网</a>的新架构以及他们从.net往java迁移的经验，他们的新架构也是做服务化和中心化，对于.net和java平台来说，迁移更多是从人力成本和一些其他因素决定的，当然，迁移最重要的还是要有公司高层的全力支持，特别重要的一点是如何让老员工也参与这个过程。因为老员工对现有系统和业务最熟悉，将他们排除在外闭门造车是注定要失败的。<br /><br />&nbsp;&nbsp;&nbsp; 最后是同样来自昆山文石的吴哲介绍如何在半天内实现一个HTML 5的游戏，他介绍的<a href="http://processingjs.org/">processing.js</a>非常有趣，processing本身是一门编程语言，有人将它移植到了js上，可以直接在支持html5上浏览器展现，效果相当cool。巧合的是我在回去后的第二天去书店的时候，竟然在某个角落看到《<a href="http://book.douban.com/subject/6517501/">processing互动编程艺术</a>》这本书，买了下来准备了解下。做数据图形化的同学可以关注下。<br /><br />&nbsp;&nbsp;&nbsp; 总体来讲，这次聚会的效果超过我的预期，在超强台风的阴影下和七夕爱情的感召下还有这么多人赶过来，作为组织者之一非常感动。并且topic讲座也让我学习了一些东西，最重要的是当面认识了一些网上交流过的朋友，给我印象深刻的是看起来非常老成的孙宁，完全不像个85后。还有个印象深刻的细节是现场的5，6台mbp，这里面还是因为有同学是在搞ROR的因素。<br /><br />&nbsp;&nbsp;&nbsp; 最后，给下slide的链接如下：<br /><br />1，我的《<a href="http://www.slideshare.net/killme2008/clojure-8785955">clojure概览</a>》，源码在<a href="https://github.com/killme2008/clojure-overview">github</a>上。<br />2，孙宁的《<a href="http://www.slideshare.net/sunng87/clojure-cnclojuremeetup">Clojure开发的生命周期管理</a>》，<a href="https://github.com/sunng87/lein-control">lein-control</a>和<a href="https://github.com/killme2008/clojure-control">clojure-control</a>。<br />3，江宏的《<a href="http://www.slideshare.net/jiangxhong/clojure-web-development-8800348">Clojure web development</a>》，他们开发的网站<br />4，吴哲的《<a href="http://www.slideshare.net/jiangxhong/how-to-build-an-html5-game-in-half-a-day">How to build a html5 game in half a day</a>》<br />5，火狐的《<a href="http://www.slideshare.net/killme2008/ss-8805669">大众点评网新架构</a>》<br />6，<a href="http://cnlojure.org/">cn-clojure主页</a><br />&nbsp;<img src ="http://www.blogjava.net/killme2008/aggbug/356106.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> 2011-08-09 14:09 <a href="http://www.blogjava.net/killme2008/archive/2011/08/09/356106.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>长三角地区的技术交流活动</title><link>http://www.blogjava.net/killme2008/archive/2011/07/27/355154.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 27 Jul 2011 08:19:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/07/27/355154.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/355154.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/07/27/355154.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/355154.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/355154.html</trackback:ping><description><![CDATA[转自 <a href="http://hjiang.net/archives/484">http://hjiang.net/archives/484</a><br /><br />Clojure-CN要组织周期性的线下技术交流活动了。如果你热爱程序设计的相关技术，并且住在长三角一带，欢迎来参与活动。只要填一下这个调查表就可以：<br /><a href=" http://www.diaochapai.com/survey548296">&nbsp;http://www.diaochapai.com/survey548296</a><br /><br />更多：<br />&nbsp;&nbsp;&nbsp; 关注我的blog的朋友应该都知道我这一年都一直在关注<a href="http://clojure.org/">clojure</a>这门语言，后来还搞了个<a href="http://groups.google.com/group/cn-clojure">cn-clojure的google group</a>。<a href="http://hjiang.net/">hjiang</a>的公司在使用clojure做商业项目，他们公司可能是国内唯一在使用clojure的商业团体，他上周跟我提起想搞这么个活动，促进对clojure学习和使用的交流，并且不局限在clojure语言本身。今年其实给自己一个目标也是去尝试推动一些事情，我对clojure纯粹是技术上的兴趣，未来也不排除去找一份专职写clojure的工作，如果你或者他（她）对clojure语言(或者函数式语言）感兴趣，欢迎来参加这次聚会，填写下这个调查表：<a href="http://www.diaochapai.com/survey548296"> http://www.diaochapai.com/survey548296</a>。<br /><br />&nbsp;&nbsp;&nbsp; 我们在调查完成后统计下大家的兴趣点和地理分布，最后决定在哪里举办，以及确定talk列表和聚会形式等。<br /><br />&nbsp;&nbsp;&nbsp; 我还申请了一个域名 <a href="http://cnlojure.org">http://cnlojure.org</a>，在github上建了个page，这件事的进展会放到这个网页上。<br /><br /><img src ="http://www.blogjava.net/killme2008/aggbug/355154.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> 2011-07-27 16:19 <a href="http://www.blogjava.net/killme2008/archive/2011/07/27/355154.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A clojure DSL for system admin and deployment with many remote machines</title><link>http://www.blogjava.net/killme2008/archive/2011/07/24/354938.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 24 Jul 2011 13:48:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/07/24/354938.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/354938.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/07/24/354938.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/354938.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/354938.html</trackback:ping><description><![CDATA[<strong>update: Allow passing command line arguments to task now.<br /><br />1.What is clojure-control?
</strong><br /> <p>&nbsp;&nbsp;&nbsp; The idea came from <a href="https://github.com/tsmith/node- control">node-control</a>.
<br /> &nbsp;&nbsp;&nbsp; Define clusters and tasks for system administration or code deployment, then execute them on one or many remote machines.
<br /> &nbsp;&nbsp;&nbsp; Clojure-control depends only on OpenSSH and clojure on the local
control machine.Remote machines simply need a standard sshd daemon.
<br /> </p><p><strong>2.Quick example
</strong><br /> </p><p>Get the current date from the two machines listed in the 'mycluster'&nbsp; config with a single command: <br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ns&nbsp;samples<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:use&nbsp;[control.core&nbsp;:only&nbsp;[task&nbsp;cluster&nbsp;scp&nbsp;ssh&nbsp;begin]]))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;define&nbsp;clusters<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cluster&nbsp;:mycluster<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:clients&nbsp;[<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;:host&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">a.domain.com</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;:user&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">alogin</span><span style="color: #000000; ">"</span><span style="color: #000000; ">}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;:host&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">b.domain.com</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;:user&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">blogin</span><span style="color: #000000; ">"</span><span style="color: #000000; ">}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;])<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;define&nbsp;tasks<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(task&nbsp;:date&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Get&nbsp;date</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; []<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ssh&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">date</span><span style="color: #000000; ">"</span><span style="color: #000000; ">))<br />&nbsp;&nbsp;&nbsp;&nbsp;;;start&nbsp;running<br />&nbsp;&nbsp;&nbsp;&nbsp;(begin) <br /></span></div><p>&nbsp;&nbsp;&nbsp; If saved in a file named "controls.clj",run with
&nbsp;&nbsp; <br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">java&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">cp&nbsp;clojure.jar:clojure</span><span style="color: #000000; ">-</span><span style="color: #000000; ">contrib.jar:control</span><span style="color: #000000; ">-</span><span style="color: #000000; ">0.1</span><span style="color: #000000; ">-</span><span style="color: #000000; ">SNAPSHOT.jar&nbsp;clojure.main&nbsp;controls.clj&nbsp;mycluster&nbsp;date <br /></span></div><p> </p><p>&nbsp;&nbsp;&nbsp; Each machine execute "date" command ,and the output form the remote
machine is printed to the console.Exmaple console output
<br /> </p><p>&nbsp;</p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;Performing&nbsp;mycluster<br />&nbsp;&nbsp;&nbsp;&nbsp;Performing&nbsp;date&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;a.domain.com<br />&nbsp;&nbsp;&nbsp;&nbsp;a.domain.com:ssh:&nbsp;date<br />&nbsp;&nbsp;&nbsp;&nbsp;a.domain.com:stdout:&nbsp;Sun&nbsp;Jul&nbsp;</span><span style="color: #000000; ">24</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">19</span><span style="color: #000000; ">:</span><span style="color: #000000; ">14</span><span style="color: #000000; ">:</span><span style="color: #000000; ">09</span><span style="color: #000000; ">&nbsp;CST&nbsp;</span><span style="color: #000000; ">2011</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;a.domain.com:exit:&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;Performing&nbsp;date&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;b.domain.com<br />&nbsp;&nbsp;&nbsp;&nbsp;b.domain.com:ssh:&nbsp;date<br />&nbsp;&nbsp;&nbsp;&nbsp;b.domain.com:stdout:&nbsp;Sun&nbsp;Jul&nbsp;</span><span style="color: #000000; ">24</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">19</span><span style="color: #000000; ">:</span><span style="color: #000000; ">14</span><span style="color: #000000; ">:</span><span style="color: #000000; ">09</span><span style="color: #000000; ">&nbsp;CST&nbsp;</span><span style="color: #000000; ">2011</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;b.domain.com:exit:&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; "> <br /></span></div><p>&nbsp;&nbsp;&nbsp; Each line of output is labeled with the address of the machine the
command was executed on. The actual command sent and the user used to
send it is displayed. stdout and stderr output of the remote process
is identified as well as the final exit code of the local ssh
command.
<br /> </p><p><strong><br /></strong></p><p><strong>3.How to scp files?
</strong><br /> &nbsp;&nbsp;&nbsp; Let's define a new task named deploy
<br /> </p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">&nbsp;&nbsp;(task&nbsp;:deploy&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">scp&nbsp;files&nbsp;to&nbsp;remote&nbsp;machines</span><span style="color: #000000; ">"</span><span style="color: #000000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; []<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(scp&nbsp;(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">release1.tar.gz</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">release2.tar.gz</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">/home/alogin/</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)) <br /></span></div><p> </p><p>&nbsp;&nbsp;&nbsp; Then it will copy release1.tar.gz and release2.tar.gz to remote
machine's /home/alogin directory.
<br /> </p><p><strong>4.Where is it?</strong><br /> </p>&nbsp;&nbsp;&nbsp; It's on github,<a title="https://github.com/killme2008/clojure-control" href="https://github.com/killme2008/clojure-control">https://github.com/killme2008/clojure-control</a><br /><br />&nbsp;&nbsp;&nbsp; Any suggestion or bug reports welcomed.<img src ="http://www.blogjava.net/killme2008/aggbug/354938.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> 2011-07-24 21:48 <a href="http://www.blogjava.net/killme2008/archive/2011/07/24/354938.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CN-Clojure群组建立</title><link>http://www.blogjava.net/killme2008/archive/2011/01/28/343727.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 28 Jan 2011 11:39:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/01/28/343727.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/343727.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/01/28/343727.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/343727.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/343727.html</trackback:ping><description><![CDATA[<br />
&nbsp;&nbsp;&nbsp; 在国内，<a href="http://clojure.org/">Clojure</a>语言的用户估计是小众中的小众，没有多少人听说，也没有多少人使用，资料也大多数是英文的，讨论也只能上国外论坛。因此，我想建立一个CN-Clojure的google group，供大家交流和学习clojure语言。群组地址（需要翻墙）：<a href="http://groups.google.com/group/cn-clojure">http://groups.google.com/group/cn-clojure</a><br />
<br />
&nbsp;&nbsp; 现在没人，就我一个<img src="/CuteSoft_Client/CuteEditor/images/emteeth.gif" alt="" align="absmiddle" border="0" />。我也会在群组里放些学习资料，欢迎任何对clojure感兴趣的朋友加入。<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/343727.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> 2011-01-28 19:39 <a href="http://www.blogjava.net/killme2008/archive/2011/01/28/343727.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Scheme interpreter in clojure</title><link>http://www.blogjava.net/killme2008/archive/2011/01/24/343423.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 24 Jan 2011 02:42:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/01/24/343423.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/343423.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/01/24/343423.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/343423.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/343423.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 昨天晚上用clojure搞了个scheme解释器，基本上是sicp里的解释器的clojure翻译版本，可能唯一值的一提的是对transient集合的使用，实现副作用的set!。总共代码包含注释才366行，支持的feature包括<br />
<br />
<table class="wiki-content-table" border="2" bordercolor="" cellpadding="" cellspacing="">
    <tbody>
        <tr>
            <th>Feature</th>
            <th>Supported</th>
            <th>Comment</th>
        </tr>
        <tr>
            <td>define</td>
            <td>yes</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>lambda</td>
            <td>yes</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>variable lookup</td>
            <td>yes</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>primitive procedure evaluation</td>
            <td>yes</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>compound procedure evaluation</td>
            <td>yes</td>
            <td>no tail recursion yet</td>
        </tr>
        <tr>
            <td>if</td>
            <td>yes</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>cond</td>
            <td>yes</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>let</td>
            <td>yes<br />
            </td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>let*</td>
            <td>yes<br />
            </td>
            <td>no named let* yet<br />
            </td>
        </tr>
        <tr>
            <td>letrec</td>
            <td>no</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>begin</td>
            <td>yes<br />
            </td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>set!</td>
            <td>yes<br />
            </td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>quote</td>
            <td>yes</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>quasiquote</td>
            <td>no</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>unquote</td>
            <td>no</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>delay</td>
            <td>no</td>
            <td><br />
            </td>
        </tr>
        <tr>
            <td>define-syntax</td>
            <td>no</td>
            <td><br />
            </td>
        </tr>
    </tbody>
</table>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 支持的primitive procedure包括常见的四则运算、car/cdr、list以及display、newline等。代码放在了github上：<a href="https://github.com/killme2008/cscheme">https://github.com/killme2008/cscheme</a>,有兴趣的可以玩玩吧。<br /><img src ="http://www.blogjava.net/killme2008/aggbug/343423.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> 2011-01-24 10:42 <a href="http://www.blogjava.net/killme2008/archive/2011/01/24/343423.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A 77 lines echo server in clojure</title><link>http://www.blogjava.net/killme2008/archive/2011/01/15/343037.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 15 Jan 2011 14:56:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2011/01/15/343037.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/343037.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2011/01/15/343037.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/343037.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/343037.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 写着玩的，不使用任何网络框架从头构建的echo server，总共77行。<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: #008080;">&nbsp;1</span>&nbsp;<span style="color: #000000;">;;Author:dennis&nbsp;(killme2008@gmail.com)<br />
</span><span style="color: #008080;">&nbsp;2</span>&nbsp;<span style="color: #000000;">(ns&nbsp;webee.network<br />
</span><span style="color: #008080;">&nbsp;3</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;(:</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;(java.nio.channels&nbsp;Selector&nbsp;SocketChannel&nbsp;ServerSocketChannel&nbsp;SelectionKey)<br />
</span><span style="color: #008080;">&nbsp;4</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(java.net&nbsp;InetSocketAddress)<br />
</span><span style="color: #008080;">&nbsp;5</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(java.nio&nbsp;ByteBuffer)<br />
</span><span style="color: #008080;">&nbsp;6</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(java.io&nbsp;IOException)))<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;">(declare&nbsp;reactor&nbsp;process</span><span style="color: #000000;">-</span><span style="color: #000000;">keys&nbsp;accept</span><span style="color: #000000;">-</span><span style="color: #000000;">channel&nbsp;read</span><span style="color: #000000;">-</span><span style="color: #000000;">channel)<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;">(defn&nbsp;bind&nbsp;[</span><span style="color: #000000;">^</span><span style="color: #000000;">InetSocketAddress&nbsp;addr&nbsp;fcol]<br />
</span><span style="color: #008080;">11</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;(let&nbsp;[selector&nbsp;(Selector</span><span style="color: #000000;">/</span><span style="color: #000000;">open)<br />
</span><span style="color: #008080;">12</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ssc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ServerSocketChannel</span><span style="color: #000000;">/</span><span style="color: #000000;">open)<br />
</span><span style="color: #008080;">13</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ag&nbsp;&nbsp;(agent&nbsp;selector)]<br />
</span><span style="color: #008080;">14</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">do</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">15</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.configureBlocking&nbsp;ssc&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">16</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(..&nbsp;ssc&nbsp;(socket)&nbsp;(bind&nbsp;addr&nbsp;</span><span style="color: #000000;">1000</span><span style="color: #000000;">))<br />
</span><span style="color: #008080;">17</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.register&nbsp;ssc&nbsp;selector&nbsp;SelectionKey</span><span style="color: #000000;">/</span><span style="color: #000000;">OP_ACCEPT)<br />
</span><span style="color: #008080;">18</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(send</span><span style="color: #000000;">-</span><span style="color: #000000;">off&nbsp;ag&nbsp;reactor&nbsp;fcol)<br />
</span><span style="color: #008080;">19</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ag)))<br />
</span><span style="color: #008080;">20</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">21</span>&nbsp;<span style="color: #000000;">(defn</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;reactor&nbsp;[</span><span style="color: #000000;">^</span><span style="color: #000000;">Selector&nbsp;selector&nbsp;fcol]<br />
</span><span style="color: #008080;">22</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;(let&nbsp;[sel&nbsp;(.&nbsp;selector&nbsp;select&nbsp;</span><span style="color: #000000;">1000</span><span style="color: #000000;">)]<br />
</span><span style="color: #008080;">23</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;sel&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">24</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[sks&nbsp;(.&nbsp;selector&nbsp;selectedKeys)]<br />
</span><span style="color: #008080;">25</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;<br />
</span><span style="color: #008080;">26</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(dorun&nbsp;(map&nbsp;(partial&nbsp;process</span><span style="color: #000000;">-</span><span style="color: #000000;">keys&nbsp;selector&nbsp;fcol)&nbsp;sks))<br />
</span><span style="color: #008080;">27</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.clear&nbsp;sks))))<br />
</span><span style="color: #008080;">28</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;(recur&nbsp;selector&nbsp;fcol)))<br />
</span><span style="color: #008080;">29</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;<br />
</span><span style="color: #008080;">30</span>&nbsp;<span style="color: #000000;">(defn</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;process</span><span style="color: #000000;">-</span><span style="color: #000000;">keys&nbsp;[</span><span style="color: #000000;">^</span><span style="color: #000000;">Selector&nbsp;selector </span><span style="color: #000000;">^</span><span style="color: #000000;">SelectionKey&nbsp;fcol&nbsp;sk]<br />
</span><span style="color: #008080;">31</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;(</span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">32</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;<br />
</span><span style="color: #008080;">33</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.isAcceptable&nbsp;sk)&nbsp;(accept</span><span style="color: #000000;">-</span><span style="color: #000000;">channel&nbsp;sk&nbsp;&nbsp;selector&nbsp;fcol)<br />
</span><span style="color: #008080;">34</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.isReadable&nbsp;sk)&nbsp;(read</span><span style="color: #000000;">-</span><span style="color: #000000;">channel&nbsp;sk&nbsp;selector&nbsp;fcol)&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">35</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;)<br />
</span><span style="color: #008080;">36</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;Throwable&nbsp;e&nbsp;(.printStackTrace&nbsp;e))))<br />
</span><span style="color: #008080;">37</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">38</span>&nbsp;<span style="color: #000000;">(defn</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;accept</span><span style="color: #000000;">-</span><span style="color: #000000;">channel&nbsp;[</span><span style="color: #000000;">^</span><span style="color: #000000;">SelectionKey&nbsp;sk </span><span style="color: #000000;">^</span><span style="color: #000000;">Selector&nbsp;selector&nbsp;fcol]<br />
</span><span style="color: #008080;">39</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;(let&nbsp;[</span><span style="color: #000000;">^</span><span style="color: #000000;">ServerSocketChannel&nbsp;ssc&nbsp;(.&nbsp;sk&nbsp;channel)<br />
</span><span style="color: #008080;">40</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #000000;">^</span><span style="color: #000000;">SocketChannel&nbsp;sc&nbsp;(.&nbsp;ssc&nbsp;accept)<br />
</span><span style="color: #008080;">41</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;created</span><span style="color: #000000;">-</span><span style="color: #000000;">fn&nbsp;(:created&nbsp;fcol)]<br />
</span><span style="color: #008080;">42</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;<br />
</span><span style="color: #008080;">43</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.configureBlocking&nbsp;sc&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">)&nbsp;<br />
</span><span style="color: #008080;">44</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.register&nbsp;sc&nbsp;selector&nbsp;SelectionKey</span><span style="color: #000000;">/</span><span style="color: #000000;">OP_READ)<br />
</span><span style="color: #008080;">45</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;created</span><span style="color: #000000;">-</span><span style="color: #000000;">fn<br />
</span><span style="color: #008080;">46</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(created</span><span style="color: #000000;">-</span><span style="color: #000000;">fn&nbsp;sc)))))<br />
</span><span style="color: #008080;">47</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">48</span>&nbsp;<span style="color: #000000;">(defn</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;close</span><span style="color: #000000;">-</span><span style="color: #000000;">channel&nbsp;[</span><span style="color: #000000;">^</span><span style="color: #000000;">SelectionKey&nbsp;sk </span><span style="color: #000000;">^</span><span style="color: #000000;">SocketChannel&nbsp;sc&nbsp;fcol]<br />
</span><span style="color: #008080;">49</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;(let&nbsp;[closed</span><span style="color: #000000;">-</span><span style="color: #000000;">fn&nbsp;(:closed&nbsp;fcol)]<br />
</span><span style="color: #008080;">50</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;<br />
</span><span style="color: #008080;">51</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.close&nbsp;sc)<br />
</span><span style="color: #008080;">52</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.cancel&nbsp;sk)<br />
</span><span style="color: #008080;">53</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;closed</span><span style="color: #000000;">-</span><span style="color: #000000;">fn&nbsp;<br />
</span><span style="color: #008080;">54</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(closed</span><span style="color: #000000;">-</span><span style="color: #000000;">fn&nbsp;sc)))))<br />
</span><span style="color: #008080;">55</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
</span><span style="color: #008080;">56</span>&nbsp;<span style="color: #000000;">(defn</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;&nbsp;read</span><span style="color: #000000;">-</span><span style="color: #000000;">channel&nbsp;[</span><span style="color: #000000;">^</span><span style="color: #000000;">SelectionKey&nbsp;sk </span><span style="color: #000000;">^</span><span style="color: #000000;">Selector&nbsp;selector&nbsp;fcol]<br />
</span><span style="color: #008080;">57</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;(let [</span><span style="color: #000000;">^</span><span style="color: #000000;">SocketChannel&nbsp;sc&nbsp;(.&nbsp;sk&nbsp;channel)<br />
</span><span style="color: #008080;">58</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #000000;">^</span><span style="color: #000000;">ByteBuffer&nbsp;buf&nbsp;(ByteBuffer</span><span style="color: #000000;">/</span><span style="color: #000000;">allocate&nbsp;</span><span style="color: #000000;">4096</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">59</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;read</span><span style="color: #000000;">-</span><span style="color: #000000;">fn&nbsp;(:read&nbsp;fcol)]<br />
</span><span style="color: #008080;">60</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">try</span><span style="color: #000000;"><br />
</span><span style="color: #008080;">61</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[n&nbsp;(.read&nbsp;sc&nbsp;buf)]<br />
</span><span style="color: #008080;">62</span>&nbsp;<span style="color: #000000;">&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;">0</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">63</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(close</span><span style="color: #000000;">-</span><span style="color: #000000;">channel&nbsp;sk&nbsp;sc&nbsp;fcol)<br />
</span><span style="color: #008080;">64</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;(.flip&nbsp;buf)<br />
</span><span style="color: #008080;">65</span>&nbsp;<span style="color: #000000;">&nbsp;&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;read</span><span style="color: #000000;">-</span><span style="color: #000000;">fn<br />
</span><span style="color: #008080;">66</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(read</span><span style="color: #000000;">-</span><span style="color: #000000;">fn&nbsp;sc&nbsp;buf)))))<br />
</span><span style="color: #008080;">67</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;IOException&nbsp;e<br />
</span><span style="color: #008080;">68</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(close</span><span style="color: #000000;">-</span><span style="color: #000000;">channel&nbsp;sk&nbsp;sc&nbsp;fcol)))))<br />
</span><span style="color: #008080;">69</span>&nbsp;<span style="color: #000000;"><br />
</span><span style="color: #008080;">70</span>&nbsp;<span style="color: #000000;">;;Bind&nbsp;a&nbsp;tcp&nbsp;server&nbsp;to&nbsp;localhost&nbsp;at&nbsp;port&nbsp;</span><span style="color: #000000;">8080</span><span style="color: #000000;">,you&nbsp;can&nbsp;telnet&nbsp;it.<br />
</span><span style="color: #008080;">71</span>&nbsp;<span style="color: #000000;">(def&nbsp;server<br />
</span><span style="color: #008080;">72</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;(bind&nbsp;<br />
</span><span style="color: #008080;">73</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;InetSocketAddress&nbsp;</span><span style="color: #000000;">8080</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">74</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;{:read&nbsp;#(.write&nbsp;</span><span style="color: #000000;">%</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">%</span><span style="color: #000000;">2</span><span style="color: #000000;">)<br />
</span><span style="color: #008080;">75</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:created&nbsp;#(println&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Accepted&nbsp;from</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;(..&nbsp;</span><span style="color: #000000;">%</span><span style="color: #000000;">&nbsp;(socket)&nbsp;(getRemoteSocketAddress)))<br />
</span><span style="color: #008080;">76</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:closed&nbsp;&nbsp;#(println&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Disconnected&nbsp;from</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;(..&nbsp;</span><span style="color: #000000;">%</span><span style="color: #000000;">&nbsp;(socket)&nbsp;(getRemoteSocketAddress)))<br />
</span><span style="color: #008080;">77</span>&nbsp;<span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}))</span></div>
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/343037.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> 2011-01-15 22:56 <a href="http://www.blogjava.net/killme2008/archive/2011/01/15/343037.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详解Clojure的递归（下）——相互递归和trampoline</title><link>http://www.blogjava.net/killme2008/archive/2010/08/22/329576.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 22 Aug 2010 05:52:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/08/22/329576.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/329576.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/08/22/329576.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/329576.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/329576.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 />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 这篇blog拖到现在才写，如果再不写，估计就只有上篇没有下篇了，趁周末写一下。<br />
<br />
&nbsp;&nbsp;&nbsp; 上篇提到了Clojure仅支持有限的TCO，不支持间接的TCO，但是有一类特殊的尾递归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;">(declare&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">odd</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">even</span><span style="color: #000000;">?</span><span style="color: #000000;">)<br />
(defn&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">odd</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;[n]<br />
&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;</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
</span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (my</span><span style="color: #000000;">-</span><span style="color: #000000;">even</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;(dec&nbsp;n))))<br />
(defn&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">even</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;[n]<br />
&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;</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
</span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (my</span><span style="color: #000000;">-</span><span style="color: #000000;">odd</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;(dec&nbsp;n))))<br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 这里使用declare做前向声明，不然在定义my-odd?的时候my-even?还没有定义，导致出错。可以看到，my-odd?调用了my-even?，而my-even?调用了my-odd?，这是一个相互递归的定义:如果n为0，那肯定不是奇数，否则就判断n-1是不是偶数，反之亦然。<br />
<br />
&nbsp;&nbsp;&nbsp; 这个递归定义看起来巧妙，但是刚才已经提到clojure通过recur支持直接的TCO优化，这个相互递归在大数计算上会导致堆栈溢出：<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;(my</span><span style="color: #000000;">-</span><span style="color: #000000;">odd</span><span style="color: #000000;">?</span><span style="color: #000000;">&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 />
<br />
user=&gt; (my-even? 10000)<br />
java.lang.StackOverflowError (NO_SOURCE_FILE:0)<br />
<br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 怎么解决呢？一个办法是转化成一个直接递归调用，定义一个parity函数，当偶数的时候返回0，当奇数的时候返回1：<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;parity&nbsp;[n]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(loop&nbsp;[n&nbsp;n&nbsp;par&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">]<br />
&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;</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;par<br />
&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;</span><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;par)))))<br />
user=&gt; (parity 3)<br />
1<br />
user=&gt; (parity 100)<br />
0<br />
user=&gt; (parity 10000)<br />
0<br />
user=&gt; (parity 10001)<br />
1</span>&nbsp;&nbsp;&nbsp; <br />
</div>
<br />
&nbsp;&nbsp;&nbsp; parity是直接的尾递归，并且使用了recur优化，重新定义my-odd和my-even就很简单了：<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;my</span><span style="color: #000000;">-</span><span style="color: #000000;">even</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;[n]&nbsp;(</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;(parity&nbsp;n)))<br />
(defn&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">odd</span><span style="color: #000000;">?</span><span style="color: #000000;">&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;">&nbsp;(parity&nbsp;n)))<br />
</span></div>
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 但是这样的方式终究不是特别优雅，相互递归的定义简洁优雅，有没有什么办法保持这个优雅的定义并且避免堆栈溢出呢？答案是trampoline，翻译过来是弹簧床，查看trampoline函数文档：<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;(doc&nbsp;trampoline)<br />
</span><span style="color: #000000;">-------------------------</span><span style="color: #000000;"><br />
clojure.core</span><span style="color: #000000;">/</span><span style="color: #000000;">trampoline<br />
([f]&nbsp;[f&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;args])<br />
&nbsp;&nbsp;trampoline&nbsp;can&nbsp;be&nbsp;used&nbsp;to&nbsp;convert&nbsp;algorithms&nbsp;requiring&nbsp;mutual<br />
&nbsp;&nbsp;recursion&nbsp;without&nbsp;stack&nbsp;consumption.&nbsp;Calls&nbsp;f&nbsp;with&nbsp;supplied&nbsp;args,&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;"><br />
&nbsp;&nbsp;any.&nbsp;If&nbsp;f&nbsp;returns&nbsp;a&nbsp;fn,&nbsp;calls&nbsp;that&nbsp;fn&nbsp;with&nbsp;no&nbsp;arguments,&nbsp;and<br />
&nbsp;&nbsp;continues&nbsp;to&nbsp;repeat,&nbsp;until&nbsp;the&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;value&nbsp;is&nbsp;not&nbsp;a&nbsp;fn,&nbsp;then<br />
&nbsp;&nbsp;returns&nbsp;that&nbsp;non</span><span style="color: #000000;">-</span><span style="color: #000000;">fn&nbsp;value.&nbsp;Note&nbsp;that&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;you&nbsp;want&nbsp;to&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;a&nbsp;fn&nbsp;as&nbsp;a<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;value,&nbsp;you&nbsp;must&nbsp;wrap&nbsp;it&nbsp;in&nbsp;some&nbsp;data&nbsp;structure&nbsp;and&nbsp;unpack&nbsp;it<br />
&nbsp;&nbsp;after&nbsp;trampoline&nbsp;returns.<br />
</span></div>
&nbsp;&nbsp; 简单来说<span style="color: #000000;">trampoline接收一个函数做参数并调用，如果结果为函数，那么就递归调用函数，如果不是，则返回结果，主要就是为了解决相互递归调用堆栈溢出的问题，查看</span><span style="color: #000000;">trampoline的定义：<br />
</span>
<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;trampoline<br />
&nbsp;&nbsp;([f]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[ret&nbsp;(f)]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(fn</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;ret)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; (recur&nbsp;ret)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; ret)))</span></div>
<br />
&nbsp;&nbsp; 看到<span style="color: #000000;">trampoline利用recur做了尾递归优化，原有的my-odd?和my-even?需要做一个小改动，就可以利用</span><span style="color: #000000;">trampoline来做递归优化了：<br />
</span>
<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;">(declare&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">odd</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">even</span><span style="color: #000000;">?</span><span style="color: #000000;">)<br />
(defn&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">odd</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;[n]<br />
&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;</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(my</span><span style="color: #000000;">-</span><span style="color: #000000;">even</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;(dec&nbsp;n))))<br />
(defn&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">even</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;[n]<br />
&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;</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(my</span><span style="color: #000000;">-</span><span style="color: #000000;">odd</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;(dec&nbsp;n))))<br />
</span></div>
&nbsp;<br />
&nbsp;&nbsp; 唯一的改动就是函数的末尾行前面加了个#，将递归调用修改成返回一个匿名函数了，使用<span style="color: #000000;">trampoline调用my-even?和my-odd?不会再堆栈溢出了：<br />
</span>
<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;(trampoline&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">odd</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10000000</span><span style="color: #000000;">)<br />
</span><span style="color: #0000ff;">false</span><span style="color: #000000;"><br />
user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(trampoline&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">even</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10000</span><span style="color: #000000;">)&nbsp;&nbsp;<br />
</span><span style="color: #0000ff;">true</span><span style="color: #000000;"><br />
user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(trampoline&nbsp;my</span><span style="color: #000000;">-</span><span style="color: #000000;">even</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1000</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1000</span><span style="color: #000000;">))<br />
</span><span style="color: #0000ff;">true</span><span style="color: #000000;"><br />
</span></div>
&nbsp;&nbsp; <br />
&nbsp;&nbsp; 弹簧床这个名称很形象，一次调用就是落到弹簧床上，如果是函数，反弹回去再来一次，如果不是，本次表演结束。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;<br /><img src ="http://www.blogjava.net/killme2008/aggbug/329576.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-08-22 13:52 <a href="http://www.blogjava.net/killme2008/archive/2010/08/22/329576.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure的transient集合</title><link>http://www.blogjava.net/killme2008/archive/2010/08/18/329257.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 18 Aug 2010 10:46:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/08/18/329257.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/329257.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/08/18/329257.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/329257.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/329257.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 下班后记一些有趣的东西。<br />
<br />
&nbsp;&nbsp;&nbsp; 这个话题是阿宝同学问我为什么clojure的PersistentVector的节点Node为什么要有个原子引用指向一个线程：<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;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Node&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;Serializable&nbsp;{<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;">transient</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;AtomicReference</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Thread</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;edit;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;Object[]&nbsp;array;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Node(AtomicReference</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Thread</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;edit,&nbsp;Object[]&nbsp;array){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.edit&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;edit;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.array&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;array;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;Node(AtomicReference</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Thread</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;edit){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.edit&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;edit;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.array&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Object[</span><span style="color: #000000;">32</span><span style="color: #000000;">];<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 我还真不懂，没有细看过这部分代码，早上花点时间学习了下。<br />
&nbsp;&nbsp;&nbsp; PersistentVector的实现是另一个话题，这里不提。我们都知道clojure的数据结构是immutable的，修改任意一个数据结构都将生成一个新的数据结构，原来的不变。为了减少复制的开销，clojure的数据结构同时是persistent，所谓持久数据结构是将数据组织为树形的层次结构，修改的时候只是root改变，指向不同的节点，原有的节点仍然复用，从而避免了大量的数据复制，具体可以搜索下<a href="http://www.google.com/url?sa=t&amp;source=web&amp;cd=1&amp;ved=0CBIQFjAA&amp;url=http%3A%2F%2Fciteseerx.ist.psu.edu%2Fviewdoc%2Fdownload%3Fdoi%3D10.1.1.21.6279%26rep%3Drep1%26type%3Dpdf&amp;rct=j&amp;q=ideal%20hash%20trees&amp;ei=Q7lrTIaCMoW0lQeC1JWZAg&amp;usg=AFQjCNGTjFqUeqzT8ldQQComx24SF4Z0ow&amp;sig2=AUL7DhTw4ZJTdYxTtSHqyQ&amp;cad=rja">ideal hash trees</a>这篇paper， paper难懂，可以看看<a href="http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation/">这篇blog</a>。<br />
<br />
&nbsp;&nbsp;&nbsp; 但是在创建PersistentVector的时候，从一堆现有的元素或者集合创建一个PersistentVector，如果每次都重新生成一个PersistentVector，未免太浪费，创建过程的性能会受到影响。我们完全可以假设创建PersistentVector这个过程肯定是线程安全的，没有必要每添加一个元素就重新生成一个PersistentVector，完全可以在同一个PersistentVector上修改。这就是TransientVector的意义所在。<br />
&nbsp;&nbsp;&nbsp; TransientVector就是一个可修改的Vector，调用它添加一个元素，删除一个元素，都是在同一个对象上进行，而不是生成新的对象。查看PersistentVector的创建：<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;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;PersistentVector&nbsp;create(ISeq&nbsp;items){<br />
&nbsp;&nbsp;&nbsp;&nbsp;TransientVector&nbsp;ret&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;EMPTY.asTransient();<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">(;&nbsp;items&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;&nbsp;items&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;items.next())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;ret.conj(items.first());<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ret.persistent();<br />
}<br />
<br />
</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;PersistentVector&nbsp;create(List&nbsp;items){<br />
&nbsp;&nbsp;&nbsp;&nbsp;TransientVector&nbsp;ret&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;EMPTY.asTransient();<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">(Object&nbsp;item&nbsp;:&nbsp;items)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;ret.conj(item);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ret.persistent();<br />
}<br />
<br />
</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;PersistentVector&nbsp;create(Object<img src="http://www.blogjava.net/Images/dot.gif"  alt="" />&nbsp;items){<br />
&nbsp;&nbsp;&nbsp;&nbsp;TransientVector&nbsp;ret&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;EMPTY.asTransient();<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">(Object&nbsp;item&nbsp;:&nbsp;items)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;ret.conj(item);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;ret.persistent();<br />
}</span></div>
<br />
<br />
&nbsp;&nbsp;&nbsp; 看到三个方法的第一步都是将EMPTY集合transient化，生成一个可修改的TransientVector：<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;">TransientVector(PersistentVector&nbsp;v){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">(v.cnt,&nbsp;v.shift,&nbsp;editableRoot(v.root),&nbsp;editableTail(v.tail));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;Node&nbsp;editableRoot(Node&nbsp;node){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Node(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;AtomicReference</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Thread</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">(<strong>Thread.currentThread()</strong>),&nbsp;node.array.clone());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<br />
&nbsp;&nbsp;&nbsp; 生成的时候记录了当前的线程在root节点。然后添加元素的时候直接调用TransientVector的conj方法，查看conj可以看到每次返回的都是this:<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;">public</span><span style="color: #000000;">&nbsp;TransientVector&nbsp;conj(Object&nbsp;val){<br />
&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;">确保修改过程合法</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ensureEditable();<br />
&nbsp;&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;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 查看ensureEditable方法：<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;">void</span><span style="color: #000000;">&nbsp;ensureEditable(){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread&nbsp;owner&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;root.edit.get();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(owner&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;Thread.currentThread())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(owner&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throw</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;IllegalAccessError(</span><span style="color: #000000;">"</span><span style="color: #000000;">Transient&nbsp;used&nbsp;by&nbsp;non-owner&nbsp;thread</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throw</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;IllegalAccessError(</span><span style="color: #000000;">"</span><span style="color: #000000;">Transient&nbsp;used&nbsp;after&nbsp;persistent!&nbsp;call</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp; }</span></div>
<br />
<br />
&nbsp;&nbsp;&nbsp; 终于看到Node中的edit引用的线程被使用了，判断当前修改的线程是否是使得集合transient化的线程，如果不是则抛出异常，这是为了保证对TransientVector的编辑是在同一个线程里，防止因为意外发布TransientVector引用引起的线程安全隐患。<br />
<br />
&nbsp;&nbsp;&nbsp; 知道了transient集合的用途，我们能在clojure中使用吗？完全没问题，clojure.core有个transient方法，可以将一个集合transient化：<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;</span><span style="color: #0000ff;">transient</span><span style="color: #000000;">&nbsp;<br />
&nbsp;&nbsp;[</span><span style="color: #000000;">^</span><span style="color: #000000;">clojure.lang.IEditableCollection&nbsp;coll]&nbsp;<br />
&nbsp;&nbsp;(.asTransient&nbsp;coll))</span></div>
&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 前提是这个集合是可编辑的，clojure的map、vector和set都是可编辑的。让我们确认下transient修改后的集合还是不是自身：<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;(def&nbsp;v1&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;</span><span style="color: #000000;">3</span><span style="color: #000000;">])<br />
#</span><span style="color: #000000;">'</span><span style="color: #000000;">user/v1</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(def&nbsp;v2&nbsp;(</span><span style="color: #0000ff;">transient</span><span style="color: #000000;">&nbsp;v1))<br />
#</span><span style="color: #000000;">'</span><span style="color: #000000;">user/v2</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;v2<br />
#</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TransientVector&nbsp;clojure.lang.PersistentVector$TransientVector@7eb366</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 定义了集合v1，v2是调用了transient之后的集合，查看v2，果然是一个<span style="color: #000000;">TransientVector。查看v2的元素个数是不是3个：<br />
</span>
<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;(.count&nbsp;v2)<br />
</span><span style="color: #000000;">3</span><span style="color: #000000;"><br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 没问题，注意，我们不能直接调用count函数，因为v2是个普通的java对象，我们必须使用dot操作符来调用java对象的方法。添加一个元素看看：<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;(def&nbsp;v3&nbsp;(.conj&nbsp;v2&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">))<br />
#</span><span style="color: #000000;">'</span><span style="color: #000000;">user/v3</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;v3<br />
#</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TransientVector&nbsp;clojure.lang.PersistentVector$TransientVector@7eb366</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 添加一个元素后形成集合v3，查看v3，跟v2是同一个对象<span style="color: #000000;">#</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">TransientVector&nbsp;clojure.lang.PersistentVector$TransientVector@7eb366</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br />
。证明了transient集合修改的是自身，而不是生成一个新集合。确认下4有加入v2和v3：<br />
</span>
<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;v3&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">)<br />
</span><span style="color: #000000;">4</span><span style="color: #000000;"><br />
user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(.count&nbsp;v2)<br />
</span><span style="color: #000000;">4</span><span style="color: #000000;"><br />
user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(.count&nbsp;v3)<br />
</span><span style="color: #000000;">4</span><span style="color: #000000;"><br />
user</span><span style="color: #000000;">=&gt;</span><span style="color: #000000;">&nbsp;(.nth&nbsp;v2&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">)<br />
</span><span style="color: #000000;">4</span><span style="color: #000000;"><br />
</span></div>
<br />
&nbsp;&nbsp;&nbsp; 果然没有问题。transient集合的使用应当慎重，除非能确认没有其他线程会去修改集合，并且对线程的可见性要求不高的时候，也许可以尝试下这个技巧。<br />
&nbsp;&nbsp; <br /><img src ="http://www.blogjava.net/killme2008/aggbug/329257.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-08-18 18:46 <a href="http://www.blogjava.net/killme2008/archive/2010/08/18/329257.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure的魅力(PPT)</title><link>http://www.blogjava.net/killme2008/archive/2010/08/17/329131.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 17 Aug 2010 10:07:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2010/08/17/329131.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/329131.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2010/08/17/329131.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/329131.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/329131.html</trackback:ping><description><![CDATA[<div style="width: 425px;" id="__ss_4987655"><strong style="margin: 12px 0pt 4px; display: block;"><a href="http://www.slideshare.net/killme2008/clojure-4987655" title="Clojure的魅力">Clojure的魅力</a></strong><object id="__sse4987655" width="637" height="532">
<param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=clojure-100817050310-phpapp01&stripped_title=clojure-4987655" />
<param name="allowFullScreen" value="true"/>
<param name="allowScriptAccess" value="always"/><embed name="__sse4987655" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=clojure-100817050310-phpapp01&stripped_title=clojure-4987655" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="637" height="532"></embed></object>
<div style="padding: 5px 0pt 12px;">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/killme2008">dennis zhuang</a>.</div>
</div>
非终稿，有兴趣先看看。<img src ="http://www.blogjava.net/killme2008/aggbug/329131.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-08-17 18:07 <a href="http://www.blogjava.net/killme2008/archive/2010/08/17/329131.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>