﻿<?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/steven2012/category/52287.html</link><description>专注&amp;坚持</description><language>zh-cn</language><lastBuildDate>Sat, 11 Aug 2012 13:04:24 GMT</lastBuildDate><pubDate>Sat, 11 Aug 2012 13:04:24 GMT</pubDate><ttl>60</ttl><item><title>Clojure的变量和全局环境</title><link>http://www.blogjava.net/steven2012/archive/2012/07/31/384387.html</link><dc:creator>steven.cui</dc:creator><author>steven.cui</author><pubDate>Mon, 30 Jul 2012 17:48:00 GMT</pubDate><guid>http://www.blogjava.net/steven2012/archive/2012/07/31/384387.html</guid><wfw:comment>http://www.blogjava.net/steven2012/comments/384387.html</wfw:comment><comments>http://www.blogjava.net/steven2012/archive/2012/07/31/384387.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/steven2012/comments/commentRss/384387.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/steven2012/services/trackbacks/384387.html</trackback:ping><description><![CDATA[<p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">原文请参考，如有问题和歧义请指正，谢谢:)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; "><a href="http://clojure.org/vars" style="color: #546188; ">http://clojure.org/vars</a></p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; "><span style="font-size: 16px; "><strong>变量和全局环境</strong></span></p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">Clojure是个很实用的语言，偶尔需要将维护和改变数据的值。她提供了4种不同的方式来操作变量：Vars, Refs, Agents, 和Atoms。Vars机制是是指向一个可改变的数据的位置，你可以为每个线程动态的绑定（制定一个新的存储位置）一个新值。Vars可以初始化根绑定(不是必须的)，绑定的值对于所有线程都是共享的，但却别的线程就不能重新绑定。因此，要么Var可以为每个线程绑定值，要么使用根绑定。</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">下面的special form def 创建了一个Var，如果Var不存在和没有给初始化，var就是不绑定的（不允许创建非动态的Var，必须显式指定根绑定）：</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (def x)<br />#'user/x<br />user=&gt; x<br />java.lang.IllegalStateException: Var user/x is unbound.</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">为根值初始化（如果存在，就被再次绑定）</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (def x 1)<br />#'user/x<br />user=&gt; x<br />1<br />&nbsp;</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">默认情况下(定义的时候初始化了根绑定），Vars是静态的(static)，但是，建立动态Var的定义可以通过元数据标记的方式，然后在线程用时通过<a href="http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/binding" style="color: #546188; ">binding</a>来指定。</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (def ^:dynamic x 1)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (def ^:dynamic y 1)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (+ x y)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">2</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (binding [x 2 y 3]</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (+ x y))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">5</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (+ x y)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">2</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">binding被创建后其他线程是是不可见的。创建的binding可以被赋值，也就是在没有离开调用堆栈之前可以被上下文访问。可以在一块代码之前设置matadata标签:dynamic来指定:</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (def ^:dynamic x 1)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">#'user/x</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (meta #'x)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">{:ns #&lt;Namespace user&gt;, :name x, :dynamic true, :line 30, :file "NO_SOURCE_PATH"}</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (binding [x 2] (println x))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">2</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">nil</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; x</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">1</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt;</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">如果你想让函数编译为static的，并且指定返回值，可以看下面的例子(速度提升不少，关键的调用函数可以采用这种方式加速)：</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;(defn fib [n]&nbsp;&nbsp; (if (&lt;= n 1)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp; 1</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp; (+ (fib (dec n)) (fib (- n 2)))))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">#'user/fib</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;(defn ^:static fib2 ^long [^long n]</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp; (if (&lt;= n 1)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp; 1</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp; (+ (fib2 (dec n)) (fib2 (- n 2)))))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">#'user/fib2</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (time (fib 38))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">"Elapsed time: 1831.113 msecs"</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">63245986</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (time (fib2 38))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">"Elapsed time: 328.715 msecs"</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">63245986</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (meta (var fib))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">{:arglists ([n]), :ns #&lt;Namespace user&gt;, :name fib, :line 1, :file "NO_SOURCE_PATH"}</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (meta (var fib2))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">{:arglists ([n]), :ns #&lt;Namespace user&gt;, :name fib2, :static true, :line 4, :file "NO_SOURCE_PATH"}</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt;</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">在上下文中可能需要重定义静态变量，从Clojure1.3开始提供<a href="http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/with-redefs" style="color: #546188; ">with-redefs</a>和<a href="http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/with-redefs-fn" style="color: #546188; ">with-redefs-fn</a>这两个宏来修改。</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">定义函数的<a href="http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/defn" style="color: #546188; ">defn</a>也是Vars的存储方式，也可以在运行时被重定义。这也为aop编程带来很多方便，例如：你可以封装一个类似logging函数给调用的上下文或者或者线程。</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; "><span style="font-size: 18px; "><strong>(set!&nbsp;var-symbol expr)</strong></span></p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">将Vars指定为special form</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">当地一个操作符为symbol的时候，它必须是全局变量。当前线程绑定的值就是后面的expr，也就是说必须是Thread-local的才可以，否则将会抛出一个使用set!来设定根绑定变量的错误。变量的表达式expr必须有返回值。</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">注意，你不能赋值给一个函数的参数或者本地绑定，只能是java的字段Vars Refs和Agents，因为这些数据在Clojure里可不变的。</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">使用set为java字段设置值，可以查看&nbsp;<a href="http://clojure.org/java_interop#set" style="color: #546188; ">Java Interop</a>.</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; "><span style="font-size: 18px; "><strong>Interning</strong></span></p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">命名空间维护了每个Var对象的全局符号映射。如果使用def定义变量没有在当前的<a href="http://clojure.org/Namespaces" style="color: #546188; ">命名空间</a>找到该符号，就创建一个，否则使用现有的。创建或者寻找的过程被称作interning。这就意味着，除非Var对象取消映射，否则Var对象每次被查询，所以请在循环中千万不要引用Var的全局变量，否则将非常慢，通过let或者binding让全局变量取消映射来提高速度。命名空间在<a href="http://clojure.org/Evaluation" style="color: #546188; ">Evaluation</a>中构建了全局环境，编译器也把所有free symbols当做Vars来解析了。</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">可以使用阅读宏(<a href="http://clojure.org/Reader" style="color: #546188; ">Reader</a>)#&#8217;来得到Var对象的内部的值。</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; "><span style="font-size: 18px; "><strong>Non-interned的类型的变量</strong></span></p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">可以通过<a href="http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/with-local-vars" style="color: #546188; ">with-local-vars</a>来创建non-interned类型的变量，在free symbol解析的时候将不会被发现，这些值只能被手工的访问，但是也可以用作当前线程的变量。</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (defn factorial [x]</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (with-local-vars [acc 1, cnt x]</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (while (&gt; @cnt 0)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (var-set acc (* @acc @cnt))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (var-set cnt (dec @cnt)))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @acc))</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">#'user/factorial</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">user=&gt; (factorial 7)</p><p style="margin: 1em 0px; color: #222222; font-family: Times; font-size: 12px; line-height: 18px; text-align: left; background-color: #ffffff; ">5040</p><img src ="http://www.blogjava.net/steven2012/aggbug/384387.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/steven2012/" target="_blank">steven.cui</a> 2012-07-31 01:48 <a href="http://www.blogjava.net/steven2012/archive/2012/07/31/384387.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Clojure 性能 tips（翻译）</title><link>http://www.blogjava.net/steven2012/archive/2012/07/29/384258.html</link><dc:creator>steven.cui</dc:creator><author>steven.cui</author><pubDate>Sun, 29 Jul 2012 06:15:00 GMT</pubDate><guid>http://www.blogjava.net/steven2012/archive/2012/07/29/384258.html</guid><wfw:comment>http://www.blogjava.net/steven2012/comments/384258.html</wfw:comment><comments>http://www.blogjava.net/steven2012/archive/2012/07/29/384258.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/steven2012/comments/commentRss/384258.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/steven2012/services/trackbacks/384258.html</trackback:ping><description><![CDATA[<p>原文章写在<a href="http://groups.google.com/group/clojure/tree/browse_frm/thread/93c664a6f3b941c3/0a451ee412dfd2c0">Google Groups thread</a>里，但是还是值得再说下。</p> <p>有朋友把Java和Clojure的一些代码片段放在Clojure Google group里比较，并提到Java的性能要比Clojure快太多了，疑问到底Clojure能不能赶上Java?</p> <p>在我的一个开源项目<a href="https://bitbucket.org/gnuvince/clj-starcraft/">clj-starcraft</a>中，关于java的性能问题，实际上也是我始终面对的，在我写这篇文章的时，我的Clojure代码还是慢了Java代码6倍(Clojure花了70秒解析了1050个文件，Java则只有12秒)</p> <p>然而，70秒对过去的速度而言不算太糟糕，在刚开始的时候，竟然花了10分钟来分析1050个文件。甚至比我用Python实现的还要慢。</p> <p>感谢Java的profiler和热情的Clojure朋友，下面列出了我在提升Clojure性能方面的一些tips:</p> <p><br /></p> <p><strong>(set! *warn-on-reflection* true)</strong></p> <p>这恐怕是最重要的一个提升：打开这个设置将会警告你在任何一处用到Java反射API的方法和属性。如你所想，直接调用永远比反射要快，不管哪里Clojure都会你不能解析这个方法，你需要自己用<a href="http://clojure.org/java_interop%23Java%20Interop-Type%20Hints">type hint</a>方式来避免反射调用。关于使用type hint，Clojure官方站点给了一个如何使用和提速的例子。</p> <p>修复所有关于<strong>*warn-on-reflection*</strong><strong>&nbsp;</strong>的编译警告后，我的clj-starcraft从10分钟降到了3分半。</p> <p><br /></p> <p><strong>强制设置数据类型</strong></p> <p>Clojure可以使用Java的<a href="http://clojure.org/java_interop%23Java%20Interop-Support%20for%20Java%20Primitives">基础数据类型</a>，无论何时在循环的时候，坚决考虑将你的值强制转换成基础类型，这将大幅提高你的性能。基础数据类型在Clojure官方网站有例子和如何进行强制转换来提高性能。</p> <p><br /></p> <p><strong>使用二元运算符</strong></p> <p>Clojure可以在一行里面支持多个表达式，但对于运算操作符，只有在两个的时候才被inlined，如果你发现自己的运算符已经超过了两个，或许该考虑重写你的代码让操作符显示的成为两个。下面请看两者之间的比较：</p> <p>user&gt; (time (dotimes [_ 1e7] (+ 2 4 5)))</p> <p>"Elapsed time: 1200.703487 msecs"</p> <p>user&gt; (time (dotimes [_ 1e7] (+ 2 (+ 4 5))))</p> <p>"Elapsed time: 241.716554 msecs"</p> <p><br /></p> <p><strong>使用==代替=</strong></p> <p>使用==比较数字来代替=，提升性能那是相当明显：</p> <p>user&gt; (time (dotimes [i 1e7] (= i i)))</p> <p>"Elapsed time: 230.797482 msecs"</p> <p>user&gt; (time (dotimes [i 1e7] (== i i)))</p> <p>"Elapsed time: 5.143681 msecs"</p> <p><br /></p> <p><strong>避免vectors的destructing binding</strong></p> <p>在一段循环种，如果你想为了提升可读性从vector中传出值，考虑下标访问来代替destructing binding。虽然代码看起来更清晰，但却非常慢。</p> <p>user&gt; (let [v [1 2 3]]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (time</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (dotimes [_ 1e7]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (let [[a b c] v]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a b c))))</p> <p>"Elapsed time: 537.239895 msecs"</p> <p>user&gt; (let [v [1 2 3]]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (time</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (dotimes [_ 1e7]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (let [a (v 0)</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b (v 1)</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c (v 2)]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a b c))))</p> <p>"Elapsed time: 12.072122 msecs"</p> <p><br /></p> <p><strong>优先使用本地变量</strong></p> <p>如果你需要在循环中查询一个值，你或许需要考虑使用本地变量(通过let定义)来代替全局变量。看下两者的时间对比：</p> <p>user&gt; (time</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (do</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (def x 1)</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (dotimes [_ 1e8]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x)))</p> <p>"Elapsed time: 372.373304 msecs"</p> <p>user&gt; (time</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (let [x 1]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (dotimes [_ 1e8]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x)))</p> <p>"Elapsed time: 3.479041 msecs"</p> <p>如果你想使用本地变量来提升性能，可以考虑下面比较土的式的方式来避免全局变量：</p> <p>(let [local-x x]</p> <p>&nbsp; (defn my-fn [a b c]</p> <p>&nbsp;&nbsp;&nbsp; ...))<br /><br /></p> <p><strong>使用profiler工具：</strong></p> <p>JVM有两个profiler工具， -Xprof和-Xrunhprof，找到程序瓶颈而不是瞎猜。</p> <p><br /></p> <p><strong>最后说明：</strong></p> <p>你已经注意到，在这些性能提升中，通过调用百万量的执行来提升了几百毫秒的性能。所以，不到万不得已需要提升性能的时候，没必要让你的代码看起来不够清晰。</p> <p><strong>原文地址:&nbsp;</strong><strong><a href="http://gnuvince.wordpress.com/2009/05/11/clojure-performance-tips/">http://gnuvince.wordpress.com/2009/05/11/clojure-performance-tips/<br /><br /></a></strong><strong>最后补充：可以通过指定编译为static方法来提高性能：<br /></strong></p><div>pasting</div><strong><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 />-->(defn<br />&nbsp;&nbsp;^{:static&nbsp;<span style="color: #0000FF; ">true</span>}<br />&nbsp;&nbsp;fib<br />&nbsp;&nbsp;[n]<br />&nbsp;&nbsp;(loop&nbsp;[a&nbsp;(<span style="color: #0000FF; ">long</span>&nbsp;1)&nbsp;b&nbsp;(<span style="color: #0000FF; ">long</span>&nbsp;1)&nbsp;i&nbsp;(<span style="color: #0000FF; ">long</span>&nbsp;1)&nbsp;r&nbsp;(list&nbsp;1&nbsp;1)]<br />&nbsp;&nbsp;&nbsp;&nbsp;(<span style="color: #0000FF; ">if</span>&nbsp;(==&nbsp;n&nbsp;i)<br />&nbsp;&nbsp;&nbsp;&nbsp;r<br />&nbsp;&nbsp;&nbsp;&nbsp;(recur&nbsp;b&nbsp;(+&nbsp;a&nbsp;b)&nbsp;(inc&nbsp;i)&nbsp;(conj&nbsp;r&nbsp;(+&nbsp;a&nbsp;b))))))</div><p>&nbsp;</p><a href="http://gnuvince.wordpress.com/2009/05/11/clojure-performance-tips/"></a></strong><p>&nbsp;</p><img src ="http://www.blogjava.net/steven2012/aggbug/384258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/steven2012/" target="_blank">steven.cui</a> 2012-07-29 14:15 <a href="http://www.blogjava.net/steven2012/archive/2012/07/29/384258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>