<nobr id="rub96"><optgroup id="rub96"></optgroup></nobr>

    <bdo id="rub96"></bdo>

      1. <track id="rub96"><div id="rub96"></div></track>
        <nobr id="rub96"><optgroup id="rub96"></optgroup></nobr>

            <nobr id="rub96"><address id="rub96"><big id="rub96"></big></address></nobr>
          1. <menuitem id="rub96"><strong id="rub96"><menu id="rub96"></menu></strong></menuitem>
            <dl id="rub96"><source id="rub96"><tr id="rub96"></tr></source></dl>
            1. <tbody id="rub96"><div id="rub96"></div></tbody>
              1. <bdo id="rub96"><optgroup id="rub96"></optgroup></bdo>
              2. <bdo id="rub96"><dfn id="rub96"><dd id="rub96"></dd></dfn></bdo>
                1. <option id="rub96"><source id="rub96"></source></option>
                2. <bdo id="rub96"></bdo>

                    <p id="rub96"><tr id="rub96"></tr></p>
                  1. <tbody id="rub96"></tbody>

                    <bdo id="rub96"></bdo>

                  2. <option id="rub96"><source id="rub96"></source></option>

                    <bdo id="rub96"><optgroup id="rub96"><dd id="rub96"></dd></optgroup></bdo>
                      <track id="rub96"></track>

                        <bdo id="rub96"></bdo>
                      1. <option id="rub96"><p id="rub96"><tr id="rub96"></tr></p></option>

                          <bdo id="rub96"></bdo>
                          1. <track id="rub96"></track>
                            1. <track id="rub96"></track>
                                  <bdo id="rub96"></bdo>
                                  <option id="rub96"></option>

                                      1. <track id="rub96"><span id="rub96"></span></track>

                                          <option id="rub96"></option>

                                          1. 
                                            
                                              <option id="rub96"><span id="rub96"></span></option>
                                              <bdo id="rub96"><address id="rub96"></address></bdo>
                                              <option id="rub96"><source id="rub96"></source></option>
                                                <nobr id="rub96"><address id="rub96"></address></nobr>
                                              1. <nobr id="rub96"><optgroup id="rub96"><big id="rub96"></big></optgroup></nobr>
                                                <track id="rub96"></track>

                                                <nobr id="rub96"><optgroup id="rub96"></optgroup></nobr>
                                                1. 莊周夢蝶

                                                  生活、程序、未來
                                                     :: 首頁 ::  ::  :: 聚合  :: 管理

                                                  置頂隨筆


                                                  很久沒有更新博客,沒想到更新是搬遷公告。這個博客累計的訪問量突破百萬,是我建立的時候完全沒有想過的事情。博客對我來說更多是記錄、記憶的地方,我時常因為想不起某個東西,來翻自己的博客,查找舊知,發現新知。閱讀很多人的博客,也是我跟蹤、學習新知的主要方式。雖然微博興起,不過博客作為更系統性的記錄的地方,不會過時。

                                                  非常感謝blogjava提供這么優秀的平臺。只是我今年給自己的一個目標是建立自己的博客,因此現在要搬遷,加上其實現在也寫的少,其實搬遷不搬遷,意義也不大了。算是一個通告,有興趣的可以訂閱我的新博客,沒興趣的請自行略過,謝謝大家。

                                                  新博客地址:http://blog.fnil.net/
                                                  RSS地址:http://blog.fnil.net/index.php/feed

                                                  新博客的第一篇記憶是《Leiningen教程中文版》,從現在開始,這個博客將不再發布任何新的文章,已有的也不會刪除,部分可能會導到我的知識庫上去。

                                                  最后,祝福blogjava越辦越好。

                                                  posted @ 2012-12-10 01:24 dennis 閱讀(11455) | 評論 (6)編輯 收藏

                                                  2012年12月10日


                                                  很久沒有更新博客,沒想到更新是搬遷公告。這個博客累計的訪問量突破百萬,是我建立的時候完全沒有想過的事情。博客對我來說更多是記錄、記憶的地方,我時常因為想不起某個東西,來翻自己的博客,查找舊知,發現新知。閱讀很多人的博客,也是我跟蹤、學習新知的主要方式。雖然微博興起,不過博客作為更系統性的記錄的地方,不會過時。

                                                  非常感謝blogjava提供這么優秀的平臺。只是我今年給自己的一個目標是建立自己的博客,因此現在要搬遷,加上其實現在也寫的少,其實搬遷不搬遷,意義也不大了。算是一個通告,有興趣的可以訂閱我的新博客,沒興趣的請自行略過,謝謝大家。

                                                  新博客地址:http://blog.fnil.net/
                                                  RSS地址:http://blog.fnil.net/index.php/feed

                                                  新博客的第一篇記憶是《Leiningen教程中文版》,從現在開始,這個博客將不再發布任何新的文章,已有的也不會刪除,部分可能會導到我的知識庫上去。

                                                  最后,祝福blogjava越辦越好。

                                                  posted @ 2012-12-10 01:24 dennis 閱讀(11455) | 評論 (6)編輯 收藏

                                                  2012年11月25日

                                                  It's my weekend project——node-shorten: URL Shortener just like t.cn,goo.gl etc.

                                                  Is is written in NodeJS,using express.js for MVC framework,and using MySQL for storage and Redis for caching.

                                                  A demo online: http://fnil.me/

                                                  The project is at https://github.com/killme2008/node-shorten

                                                  Feel free to modify and use it.Have fun.

                                                  posted @ 2012-11-25 20:31 dennis| 編輯 收藏

                                                  2012年9月25日

                                                  很久沒寫博客,一是工作忙,二是沒有太多的事情可說。

                                                  最近在公司大佬的支持下,建立了一個Clojure語言中文方面的博客和問答網站,歡迎任何對Clojure這門基于JVM之上的函數式語言感興趣的童鞋貢獻原創文章或者資料,申請帳號請看這里

                                                  博客地址:  http://blog.clojure.cn/
                                                  問答網站:  http://ask.clojure.cn/

                                                  歡迎轉發和注冊使用,謝謝。

                                                  郵件列表仍然使用google group:https://groups.google.com/group/cn-clojure/

                                                  posted @ 2012-09-25 12:51 dennis 閱讀(11552) | 評論 (4)編輯 收藏

                                                  2012年7月18日

                                                  Home: https://github.com/killme2008/ring.velocity

                                                  A Clojure library designed to render velocity template for ring in clojure.

                                                  Usage

                                                  Adds dependency in leiningen project.clj:

                                                    [ring.velocity "0.1.0-SNAPSHOT"] 

                                                  Create a directory named templates in your project directory to keep all velocity templates.

                                                  Create a template templates/test.vm:

                                                    hello,$name,your age is $age. 

                                                  Use ring.velocity in your namespace:

                                                    (use '[ring.velocity.core :only [render]]) 

                                                  Use render function to render template with vars:

                                                    (render "test.vm" :name "dennis" :age 29) 

                                                  The test.vm will be interpreted equals to:

                                                    hello,dennis,your age is 29. 

                                                  Use ring.velocity in compojure:

                                                    (defroutes app-routes      
                                                  (GET "/" [] (render "test.vm" :name "dennis" :age 29))
                                                  (route/not-found "Not Found"))

                                                  Use ring.velocity in ring:

                                                    (use '[ring.util.response])   
                                                  (response (render "test.vm" :name "dennis" :age 29))

                                                  Custom velocity properties,just put a file named ring-velocity.properties to your classpath or resource paths.The default velocity properties is in src/default/velocity.properties.

                                                  License

                                                  Copyright © 2012 dennis zhuang[killme2008@gmail.com]

                                                  Distributed under the Eclipse Public License, the same as Clojure.

                                                  Home: https://github.com/killme2008/ring.velocity

                                                  posted @ 2012-07-18 00:07 dennis 閱讀(9202) | 評論 (0)編輯 收藏

                                                  2012年7月10日


                                                      Clojure的一大優點就是跟Java語言的完美配合,Clojure和Java之間可以相互調用,Clojure可以天然地使用Java平臺上的豐富資源。在Clojure里調用一個類的方法很簡單,利用dot操作符:

                                                  user=> (.substring "hello" 3)
                                                  "lo"
                                                  user=> (.substring "hello" 0 3)
                                                  "hel"

                                                      上面的例子是在clojure里調用String的substring方法做字符串截取。Clojure雖然是一門弱類型的語言,但是它的Lisp Reader還是能識別大多數常見的類型,比如這里hello是一個字符串就可以識別出來,3是一個整數也可以,通過這些類型信息可以找到最匹配的substring方法,在生成字節碼的時候避免使用反射,而是直接調用substring方法(INVOKEVIRTUAL指令)。

                                                      但是當你在函數里調用類方法的時候,情況就變了,例如,定義substr函數:
                                                  (defn substr [s begin end] (.substring s begin end))

                                                      我們打開*warn-on-reflection*選項,當有反射的時候告警:

                                                  user=> (set! *warn-on-reflection* true)
                                                  true
                                                  user=> (defn substr [s begin end] (.substring s begin end))
                                                  Reflection warning, NO_SOURCE_PATH:22 - call to substring can't be resolved.
                                                  #'user/substr
                                                     
                                                      問題出現了,由于函數substr里沒有任何關于參數s的類型信息,為了調用s的substring方法,必須使用反射來調用,clojure編譯器也警告我們調用substring沒辦法解析,只能通過反射調用。眾所周知,反射調用是個相對昂貴的操作(對比于普通的方法調用有)。這一切都是因為clojure本身是弱類型的語言,對參數或者返回值你不需要聲明類型而直接使用,Clojure會自動處理類型的轉換和調用。ps.在leiningen里啟用反射警告很簡單,在project.clj里設置:

                                                  ;; Emit warnings on all reflection calls.
                                                    :warn-on-reflection true
                                                     
                                                  過多的反射調用會影響效率,有沒有辦法避免這種情況呢?有的,Clojure提供了type hint機制,允許我們幫助編譯器來生成更高效的字節碼。所謂type hint就是給參數或者返回值添加一個提示:hi,clojure編譯器,這是xxx類型,我想調用它的yyy方法,請生成最高效的調用代碼,謝謝合作:
                                                  user=> (defn substr [^String s begin end] (.substring s begin end))
                                                  #'user/substr
                                                       
                                                      這次沒有警告,^String就是參數s的type hint,提示clojure編譯器說s的類型是字符串,那么clojure編譯器會從java.lang.String類里查找名稱為substring并且接收兩個參數的方法,并利用invokevirtual指令直接調用此方法,避免了反射調用。除了target對象(這里的s)可以添加type hint,方法參數和返回值也可以添加type hint:
                                                  user=> (defn ^{:tag String} substr [^String s ^Integer begin ^Integer end] (.substring s begin end))
                                                  #'user/substr
                                                      
                                                      返回值添加type hint是利用tag元數據,提示substr的返回類型是String,其他函數在使用substr的時候可以利用這個類型信息來避免反射;而參數的type hint跟target object的type hint一樣以^開頭加上類型,例如這里begin和end都提示說是Integer類型。

                                                      問題1,什么時候應該為參數添加type hint呢?我的觀點是,在任何為target object添加type hint的地方,都應該相應地為參數添加type hint,除非你事先不知道參數的類型。為什么呢?因為clojure查找類方法的順序是這樣:

                                                  1.從String類里查找出所有參數個數為2并且名稱為substring方法
                                                  2.遍歷第一步里查找出來的Method,如果你有設置參數的type hint,則
                                                  查找最匹配參數類型的Method;否則,如果第一步查找出來的Method就一個,直接使用這個Method,相反就認為沒有找到對應的Method。
                                                  3.如果第二步沒有找到Method,使用反射調用;否則根據該Method元信息生成調用字節碼。

                                                     因此,如果substring方法的兩個參數版本剛好就一個,方法參數有沒有type hint都沒有關系(有了錯誤的type hint反而促使反射的發生),我們都會找到這個唯一的方法;但是如果目標方法的有多個重載方法并且參數相同,而只是參數類型不同(Java里是允許方法的參數類型重載的,Clojure只允許函數的參數個數重載),那么如果沒有方法參數的type hint,Clojure編譯器仍然無法找到合適的調用方法,而只能通過反射。
                                                     
                                                     看一個例子,定義get-bytes方法調用String.getBytes:

                                                  user=> (defn get-bytes [s charset] (.getBytes s charset))
                                                  Reflection warning, NO_SOURCE_PATH:26 - call to getBytes can't be resolved.
                                                  #'user/get-bytes
                                                  user=> (defn get-bytes [^String s charset] (.getBytes s charset))
                                                  Reflection warning, NO_SOURCE_PATH:27 - call to getBytes can't be resolved.
                                                  #'user/get-bytes

                                                      第一次定義,s和charset都沒有設置type hint,有反射警告;第二次,s設置了type hint,但是還是有反射警告。原因就在于String.getBytes有兩個重載方法,參數個數都是一個,但是接收不同的參數類型,一個是String的charset名稱,一個Charset對象。如果我們明確地知道這里charset是字符串,那么還可以為charset添加type hint:
                                                  user=> (defn get-bytes [^String s ^String charset] (.getBytes s charset))
                                                  #'user/get-bytes
                                                     
                                                      這次才真正的沒有警告了。總結:在設置type hint的時候,不要只考慮被調用的target object,也要考慮調用的方法參數。

                                                      問題2:什么時候應該添加tag元數據呢?理論上,在任何你明確知道返回類型的地方都應該添加tag,但是這不是教條,如果一個偶爾被調用的方法是無需這樣做的。這一點只對寫庫的童鞋要特別注意。

                                                      Type hint的原理在上文已經大概描述了下,具體到clojure源碼級別,請參考clojure.lang.Compiler.InstanceMethodExpr類的構造函數和emit方法。最后,附送是否使用type hint生成substr函數的字節碼之間的差異對比:
                                                  未使用type hint 使用type hint

                                                    // access flags 1

                                                    public invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

                                                     L0

                                                      LINENUMBER 14 L0

                                                     L1

                                                      LINENUMBER 14 L1

                                                      ALOAD 1

                                                      ACONST_NULL

                                                      ASTORE 1

                                                      LDC "substring"

                                                      ICONST_2

                                                      ANEWARRAY java/lang/Object

                                                      DUP

                                                      ICONST_0

                                                      ALOAD 2

                                                      ACONST_NULL

                                                      ASTORE 2

                                                      AASTORE

                                                      DUP

                                                      ICONST_1

                                                      ALOAD 3

                                                      ACONST_NULL

                                                      ASTORE 3

                                                      AASTORE

                                                      INVOKESTATIC clojure/lang/Reflector.invokeInstanceMethod (Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;

                                                     L2

                                                      LOCALVARIABLE this Ljava/lang/Object; L0 L2 0

                                                      LOCALVARIABLE s Ljava/lang/Object; L0 L2 1

                                                      LOCALVARIABLE begin Ljava/lang/Object; L0 L2 2

                                                      LOCALVARIABLE end Ljava/lang/Object; L0 L2 3

                                                      ARETURN

                                                      MAXSTACK = 0

                                                      MAXLOCALS = 0

                                                  public invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

                                                     L0

                                                      LINENUMBER 15 L0

                                                     L1

                                                      LINENUMBER 15 L1

                                                      ALOAD 1

                                                      ACONST_NULL

                                                      ASTORE 1

                                                      CHECKCAST java/lang/String

                                                      ALOAD 2

                                                      ACONST_NULL

                                                      ASTORE 2

                                                      CHECKCAST java/lang/Number

                                                      INVOKESTATIC clojure/lang/RT.intCast (Ljava/lang/Object;)I

                                                      ALOAD 3

                                                      ACONST_NULL

                                                      ASTORE 3

                                                      CHECKCAST java/lang/Number

                                                      INVOKESTATIC clojure/lang/RT.intCast (Ljava/lang/Object;)I

                                                      INVOKEVIRTUAL java/lang/String.substring (II)Ljava/lang/String;

                                                     L2

                                                      LOCALVARIABLE this Ljava/lang/Object; L0 L2 0

                                                      LOCALVARIABLE s Ljava/lang/Object; L0 L2 1

                                                      LOCALVARIABLE begin Ljava/lang/Object; L0 L2 2

                                                      LOCALVARIABLE end Ljava/lang/Object; L0 L2 3

                                                      ARETURN

                                                      MAXSTACK = 0

                                                      MAXLOCALS = 0


                                                      
                                                      對比很明顯,沒有使用type hint,調用clojure.lang.Reflector的invokeInstanceMethod方法,使用反射調用(具體見clojure.lang.Reflector.java),而使用了type hint之后,則直接使用invokevirtual指令(其他方法可能是invokestatic或者invokeinterface等指令)調用該方法,避免了反射。
                                                        

                                                      參考:

                                                  posted @ 2012-07-10 20:37 dennis 閱讀(11412) | 評論 (1)編輯 收藏

                                                  2012年6月15日


                                                      HouseMD是淘寶的聚石寫的一個非常優秀的Java進程運行時診斷和調試工具,如果你接觸過btrace,那么HouseMD也許你應該嘗試下,它比btrace更易用,不需要寫腳本,類似strace的方式attach到jvm進程做跟蹤調試。

                                                      基本的安裝和使用請看這篇文檔《UserGuide》,恕不重復。以下內容都假設你正確安裝了housemd。

                                                      本文主要介紹下怎么用housemd診斷跟蹤clojure進程。Clojure的java實現也是跑在JVM里,當然也可以用housemd。

                                                      我們以一個簡單的例子開始,假設我們有如下clojure代碼:
                                                  (loop [x 1]
                                                    (Thread/sleep 1000)
                                                    (prn x)
                                                    (recur (inc x)))

                                                      這段很簡單,只是間隔一秒不斷地打印遞增的數字x。我們準備用housemd跟蹤這個程序的運行,首先運行這個程序,你可以用lein,也可以直接java命令運行:
                                                  java -cp clojure.jar clojure.main test.clj

                                                      運行時不斷地在控制臺打印數字,通過jps或者ps查詢到該進程的id,假設為pid,使用housemd連接到該進程:
                                                  housemd <pid>
                                                      順利進入housemd的交互控制臺,通過help命令可以查詢支持的命令:

                                                  housemd> help

                                                  quit      terminate the process.
                                                  help      display this infomation.
                                                  trace     display or output infomation of method invocaton.
                                                  loaded    display loaded classes information.

                                                      要用housemd調試clojure,你需要對clojure的實現有一點點了解,有興趣可以看過去的一篇blog《clojure hacking guide》,簡單來說,clojure的編譯器會將clojure代碼編譯成java類并運行。對于JVM來說,clojure生成的類,跟java編譯器生成類沒有什么不同。
                                                      具體到上面的clojure代碼,會生成一個名為user$eval1的類,user是默認的namespace,而eval1是clojure編譯器自動生成的一個標示類名,通過loaded命令查詢類的加載情況:
                                                  housemd> loaded user$eval1 -h
                                                  user$eval1 -> null
                                                      - clojure.lang.DynamicClassLoader@1d25d06e
                                                          - clojure.lang.DynamicClassLoader@1d96f4b5
                                                              - sun.misc.Launcher$AppClassLoader@a6eb38a
                                                                  - sun.misc.Launcher$ExtClassLoader@69cd2e5f

                                                      通過-h選項打印了加載user$eval1的類加載器的層次關系,因為user$eval1是動態生成的(clojure啟動過程中),因此它不在任何一個class或者jar文件中。除了查詢user namespace的類之外,你還可以查詢clojure.core,clojure.lang,clojure.java等任何被加載進來的類,例如查詢clojure.core.prn的類,在clojure里這是一個函數,在jvm看來這只是一個類:
                                                  housemd> loaded -h core$prn
                                                  clojure.core$prn -> /Volumes/HDD/Users/apple/clojure/clojure.jar
                                                      - sun.misc.Launcher$AppClassLoader@a6eb38a
                                                          - sun.misc.Launcher$ExtClassLoader@69cd2e5f
                                                     注意,不需要完整的namespace——clojure.core,直接core$prn即可。其他也是類似。小技巧:如果你實在不知道clojure編譯器生成的類名,你可以利用jvm自帶的jmap命令來查詢。

                                                     接下來,我們嘗試用trace命令跟蹤方法的運行,例如例子中的clojure代碼用到了loop和recur兩個sepcial form,我們跟蹤下loop:
                                                  housemd> trace -t 5 core$loop
                                                  INFO : probe class clojure.core$loop
                                                  core$loop.doInvoke(Object, Object, Object, Object)    sun.misc.Launcher$AppClassLoader@a6eb38a            0            -ms    null
                                                  core$loop.getRequiredArity()                          sun.misc.Launcher$AppClassLoader@a6eb38a            0            -ms    null

                                                  core$loop.doInvoke(Object, Object, Object, Object)    sun.misc.Launcher$AppClassLoader@a6eb38a            0            -ms    null
                                                  core$loop.getRequiredArity()                          sun.misc.Launcher$AppClassLoader@a6eb38a            0            -ms    null

                                                  core$loop.doInvoke(Object, Object, Object, Object)    sun.misc.Launcher$AppClassLoader@a6eb38a            0            -ms    null
                                                  core$loop.getRequiredArity()                          sun.misc.Launcher$AppClassLoader@a6eb38a            0            -ms    null

                                                  core$loop.doInvoke(Object, Object, Object, Object)    sun.misc.Launcher$AppClassLoader@a6eb38a            0            -ms    null
                                                  core$loop.getRequiredArity()                          sun.misc.Launcher$AppClassLoader@a6eb38a            0            -ms    null

                                                  core$loop.doInvoke(Object, Object, Object, Object)    sun.misc.Launcher$AppClassLoader@a6eb38a            0            -ms    null
                                                  core$loop.getRequiredArity()                          sun.misc.Launcher$AppClassLoader@a6eb38a            0            -ms    null

                                                  INFO : Ended by timeout
                                                  INFO : reset class clojure.core$loop

                                                      在5秒內,clojure.core$loop類有兩個方法各被調用了5次,doInvoke是實際的調用,而getRequiredArity用來查詢loop所需要的參數個數。trace還可以跟蹤到具體的方法,例如我們跟蹤prn函數的調用情況:
                                                  housemd> trace -t 5 core$prn.doInvoke
                                                  INFO : probe class clojure.core$prn
                                                  core$prn.doInvoke(Object)    sun.misc.Launcher$AppClassLoader@a6eb38a            1            1ms    clojure.core$prn@3e4ac866

                                                  core$prn.doInvoke(Object)    sun.misc.Launcher$AppClassLoader@a6eb38a            2           <1ms    clojure.core$prn@3e4ac866

                                                  core$prn.doInvoke(Object)    sun.misc.Launcher$AppClassLoader@a6eb38a            3           <1ms    clojure.core$prn@3e4ac866

                                                  core$prn.doInvoke(Object)    sun.misc.Launcher$AppClassLoader@a6eb38a            4           <1ms    clojure.core$prn@3e4ac866

                                                  core$prn.doInvoke(Object)    sun.misc.Launcher$AppClassLoader@a6eb38a            5           <1ms    clojure.core$prn@3e4ac866

                                                  INFO : Ended by timeout
                                                  INFO : reset class clojure.core$prn
                                                    
                                                     trace打印了方法的調用次數(5秒內)和每次調用的時間(毫秒級別),以及調用的target object。小技巧:沒有可變參數的函數生成類最終調用的是invoke方法(參數個數可能重載),有可變參數的函數調用的是doInvoke方法。

                                                     trace命令還支持打印調用堆棧到文件,例如:
                                                  trace -t 5 -d -s  core$prn.doInvoke

                                                     利用-s和-d命令會將詳細的調用信息輸出到臨時目錄,臨時目錄的路徑可以通過trace help命令查詢到,在我的機器上是/tmp/trace/<pid>@host目錄下。調用堆棧的輸出類似:
                                                  example$square.invoke(Long) call by thread [main]
                                                      example$eval9.invoke(test.clj:11)
                                                      clojure.lang.Compiler.eval(Compiler.java:6465)
                                                      clojure.lang.Compiler.load(Compiler.java:6902)
                                                      clojure.lang.Compiler.loadFile(Compiler.java:6863)
                                                      clojure.main$load_script.invoke(main.clj:282)
                                                      clojure.main$script_opt.invoke(main.clj:342)
                                                      clojure.main$main.doInvoke(main.clj:426)
                                                      clojure.lang.RestFn.invoke(RestFn.java:421)
                                                      clojure.lang.Var.invoke(Var.java:405)
                                                      clojure.lang.AFn.applyToHelper(AFn.java:163)
                                                      clojure.lang.Var.applyTo(Var.java:518)
                                                      clojure.main.main(main.java:37)

                                                     上面這個簡單的例子展示了使用housemd跟蹤診斷clojure進程的方法。

                                                     自定義ns和函數的調試與此類似,假設我們有下面的clojure代碼:
                                                  (ns example)
                                                  (defn square [x]
                                                    (* x x))

                                                  (loop [x 1]
                                                    (Thread/sleep 1000)
                                                    (square x)
                                                    (recur (inc x)))
                                                   
                                                     ns為example,自定義函數square并定期循環調用。使用housemd診斷這段代碼:
                                                  loaded -h example$square     #查詢square的加載情況
                                                  trace -t 10 -d -s example$square.invoke  #跟蹤10秒內square的調用情況

                                                  posted @ 2012-06-15 02:52 dennis 閱讀(11801) | 評論 (2)編輯 收藏

                                                  2012年6月4日

                                                  我們在維護的淘寶開源消息中間件的metaqgithub分支,今天發布了1.4.2版本,主要做了如下改進:

                                                  1.支持發送和訂閱分離,可以細粒度地控制Broker或者某個Topic是否接收消息和接受訂閱。服務端添加新選項acceptPublish和acceptSubscribe。

                                                  2.更友好地關閉Broker,梳理關閉流程并通過JMX調用方法關閉替代原來簡單的kill。

                                                  3.更新python客戶端到0.2版本,可以通過pip安裝:  pip install metaq

                                                  4.發布ruby語言客戶端meta-ruby 0.1版本。

                                                  5.其他小改進:升級gecko到1.1.1版本,升級quartz到2.1.4版本,添加集成測試工程和內部重構等。

                                                  6.新文檔《使用log4j擴展發送消息》

                                                  簡介:https://github.com/killme2008/Metamorphosis/wiki/介紹
                                                  下載:https://github.com/killme2008/Metamorphosis/downloads

                                                  文檔:https://github.com/killme2008/Metamorphosis/wiki

                                                  posted @ 2012-06-04 10:03 dennis 閱讀(10958) | 評論 (1)編輯 收藏

                                                  2012年5月22日


                                                      你有個任務,需要用到某個開源項目;或者老大交代你一個事情,讓你去了解某個東西。怎么下手呢?如何開始呢?我的習慣是這樣:

                                                  1.首先,查找和閱讀該項目的博客和資料,通過google你能找到某個項目大體介紹的博客,快速閱讀一下就能對項目的目的、功能、基本使用有個大概的了解。

                                                  2.閱讀項目的文檔,重點關注類似Getting started、Example之類的文檔,從中學習如何下載、安裝、甚至基本使用該項目所需要的知識。

                                                  3.如果該項目有提供現成的example工程,首先嘗試按照開始文檔的介紹運行example,如果運行順利,那么恭喜你順利開了個好頭;如果遇到問題,首先嘗試在項目的FAQ等文檔里查找答案,再次,可以將問題(例如異常信息)當成關鍵詞去搜索,查找相關的解決辦法,你遇到了,別人一般也會遇到,熱心的朋友會記錄下解決的過程;最后,可以將問題提交到項目的郵件列表,請大家幫你看看。在沒有成功運行example之前,不要嘗試修改example。

                                                  4.運行了第一個example之后,嘗試根據你的理解和需要修改example,測試高級功能等。

                                                  5.在了解基本使用后,需要開始深入的了解該項目。例如項目的配置管理、高級功能以及最佳實踐。通常一個運作良好的項目會提供一份從淺到深的用戶指南,你并不需要從頭到尾閱讀這份指南,根據時間和興趣,特別是你自己任務的需要,重點閱讀部分章節并做筆記(推薦evernote)。

                                                  6.如果時間允許,嘗試從源碼構建該項目。通常開源項目都會提供一份構建指南,指導你如何搭建一個用于開發、調試和構建的環境。嘗試構建一個版本。

                                                  7.如果時間允許并且有興趣,可以嘗試閱讀源碼:
                                                  (1)閱讀源碼之前,查看該項目是否提供架構和設計文檔,閱讀這些文檔可以了解該項目的大體設計和結構,讀源碼的時候不會無從下手。
                                                  (2)閱讀源碼之前,一定要能構建并運行該項目,有個直觀感受。
                                                  (3)閱讀源碼的第一步是抓主干,嘗試理清一次正常運行的代碼調用路徑,這可以通過debug來觀察運行時的變量和行為。修改源碼加入日志和打印可以幫助你更好的理解源碼。
                                                  (4)適當畫圖來幫助你理解源碼,在理清主干后,可以將整個流程畫成一張流程圖或者標準的UML圖,幫助記憶和下一步的閱讀。
                                                  (5)挑選感興趣的“枝干”代碼來閱讀,比如你對網絡通訊感興趣,就閱讀網絡層的代碼,深入到實現細節,如它用了什么庫,采用了什么設計模式,為什么這樣做等。如果可以,debug細節代碼。
                                                  (6)閱讀源碼的時候,重視單元測試,嘗試去運行單元測試,基本上一個好的單元測試會將該代碼的功能和邊界描述清楚。
                                                  (7)在熟悉源碼后,發現有可以改進的地方,有精力、有意愿可以向該項目的開發者提出改進的意見或者issue,甚至幫他修復和實現,參與該項目的發展。

                                                  8.通常在閱讀文檔和源碼之后,你能對該項目有比較深入的了解了,但是該項目所在領域,你可能還想搜索相關的項目和資料,看看有沒有其他的更好的項目或者解決方案。在廣度和深度之間權衡。

                                                      以上是我個人的一些習慣,我自己也并沒有完全按照這個來,但是按照這個順序,基本上能讓你比較高效地學習和使用某個開源項目。

                                                  posted @ 2012-05-22 23:12 dennis 閱讀(23639) | 評論 (9)編輯 收藏

                                                  2012年5月19日


                                                      很久沒更新博客了,在北京工作,忙碌并且充實。目前來說,Clojure最好的開發編輯器應該是Emacs + Slime的組合,利用swank-clojure這個項目,加上clojure-mode,可以完美地運行slime。編譯、運行、跳轉、文檔和引用查看甚至debug都可以搞定。具體配置恕不重復,看swank-clojure的文檔即可自己安裝起來,或者這篇中文博客windows上配置

                                                      分享幾個Tip,也期待大家分享你們的使用心得。

                                                      首先是自動在打開clj后綴文件的時候啟動執行clojure-jack-in與slime連接,可以在emacs配置里加上個callback:

                                                  (eval-after-load "clojure-mode"
                                                    '(progn
                                                       (require 'slime)
                                                       (require 'clojure-mode)
                                                       (unless (slime-connected-p)
                                                         (save-excursion (clojure-jack-in)))))
                                                      這樣在打開clj為后綴的文件的時候,將自動啟動clojure-mode執行clojure-jack-in函數并且連接slime。

                                                      將clj后綴的文件自動關聯到clojure-mode:
                                                  (setq auto-mode-alist (cons '("\\.clj$" . clojure-mode) auto-mode-alist))
                                                      通常來說如果你是利用marmalade安裝的,會自動關聯的。

                                                      另外,啟動自動匹配括號、字符串引號等的paredit模式一定要啟動:
                                                  (defun paredit-mode-enable () (paredit-mode 1))
                                                  (add-hook 'clojure-mode-hook 'paredit-mode-enable)
                                                  (add-hook 'clojure-test-mode-hook 'paredit-mode-enable)

                                                     在使用clojure-mode或者clojure-test-mode的時候自動啟用paredit模式,括號再也不是問題。括號匹配提示一般是開啟的,如果沒有,強制開啟:

                                                  ;;    顯示括號匹配
                                                  (show-paren-mode t)
                                                  (setq show-paren-style 'parentheses)

                                                      slime更多配置,啟用IO重定向(多線程IO輸出都定向到SLIME repl)以及設置通訊字符編碼等:

                                                  (eval-after-load "slime"
                                                    '(progn
                                                       (slime-setup '(slime-repl slime-fuzzy))
                                                       ;;(setq slime-truncate-lines t)
                                                       (setq  swank:*globally-redirect-io*  t)
                                                       ;; (setq slime-complete-symbol-function ' slime-fuzzy-complete-symbol)
                                                       (setq slime-net-coding-system 'utf-8-unix)))

                                                      細心的朋友可能注意到我注釋了slime-fuzzy-complete的配置,這是一個支持更好的自動補全功能的SLIME插件(可以用縮寫來自動補全),可惜在我機器上沒有嘗試配置成功,有興趣你可以嘗試下。

                                                      在REPL里支持語法高亮,一定要配置上:

                                                  (add-hook 'slime-repl-mode-hook
                                                            (defun clojure-mode-slime-font-lock ()
                                                              (require 'clojure-mode)
                                                              (let (font-lock-mode)
                                                                (clojure-mode-font-lock-setup))))

                                                      單獨在clojure-mode(在其他mode里這些快捷鍵不會起作用)里配置快捷鍵可以這樣:
                                                  (eval-after-load "clojure-mode"
                                                    '(progn
                                                       (require 'slime)
                                                       (require 'clojure-mode)
                                                       (define-key clojure-mode-map (kbd "M-/")  (quote slime-complete-symbol))
                                                       (define-key clojure-mode-map (kbd "C-c s")  (quote slime-selector)))

                                                     例如我這里將M-/作為自動補全的快捷鍵,因為meta鍵在我的Mac機器上設置為command鍵,因此自動補全的操作習慣就跟Eclipse類似。而slime-selector是一個非常有用的函數,用來跳轉到slime的一系列buffer,因此我綁定了C-c s快捷鍵。

                                                      額外一提,在Mac osx下,將command作為meta鍵:
                                                  ;;; I prefer cmd key for meta
                                                  (setq mac-option-key-is-meta nil
                                                        mac-command-key-is-meta t
                                                        mac-command-modifier 'meta
                                                        mac-option-modifier 'none)

                                                      最后,期待大家不吝分享你的心得。
                                                      

                                                  posted @ 2012-05-19 00:57 dennis 閱讀(14894) | 評論 (11)編輯 收藏

                                                  2012年5月12日


                                                      My weekend project clj.monitor is beta release,it's a clojure DSL for monitoring system and applications based on SSH.

                                                  Home:https://github.com/killme2008/clj.monitor

                                                  An example:
                                                  (ns clj.monitor.example
                                                    (:use [clj.monitor.core]
                                                          [control.core]
                                                          [clj.monitor.tasks]))

                                                  ;;define a mysql cluster
                                                  (defcluster mysql
                                                    :clients [{:user "deploy" :host "mysql.app.com"}])

                                                  ;;define a monitor for mysql cluster
                                                  (defmonitor mysql-monitor
                                                    :tasks [(ping-mysql "root" "password")
                                                              (system-load :5 3)]
                                                    :clusters [:mysql])

                                                  ;;start monitors
                                                  (start-monitors
                                                   :cron "* 0/5 * * * ?"
                                                   :alerts [(mail :from "alert@app.com" :to "yourname@app.com")]
                                                   :monitors [mysql-monitor])

                                                  API document: http://fnil.net/clj.monitor

                                                  It is just a beta release,if you have any questions or find issues ,please let me know,thanks.

                                                  posted @ 2012-05-12 22:38 dennis 閱讀(8963) | 評論 (5)編輯 收藏

                                                  精准平特三肖
                                                  <nobr id="rub96"><optgroup id="rub96"></optgroup></nobr>

                                                  <bdo id="rub96"></bdo>

                                                    1. <track id="rub96"><div id="rub96"></div></track>
                                                      <nobr id="rub96"><optgroup id="rub96"></optgroup></nobr>

                                                          <nobr id="rub96"><address id="rub96"><big id="rub96"></big></address></nobr>
                                                        1. <menuitem id="rub96"><strong id="rub96"><menu id="rub96"></menu></strong></menuitem>
                                                          <dl id="rub96"><source id="rub96"><tr id="rub96"></tr></source></dl>
                                                          1. <tbody id="rub96"><div id="rub96"></div></tbody>
                                                            1. <bdo id="rub96"><optgroup id="rub96"></optgroup></bdo>
                                                            2. <bdo id="rub96"><dfn id="rub96"><dd id="rub96"></dd></dfn></bdo>
                                                              1. <option id="rub96"><source id="rub96"></source></option>
                                                              2. <bdo id="rub96"></bdo>

                                                                  <p id="rub96"><tr id="rub96"></tr></p>
                                                                1. <tbody id="rub96"></tbody>

                                                                  <bdo id="rub96"></bdo>

                                                                2. <option id="rub96"><source id="rub96"></source></option>

                                                                  <bdo id="rub96"><optgroup id="rub96"><dd id="rub96"></dd></optgroup></bdo>
                                                                    <track id="rub96"></track>

                                                                      <bdo id="rub96"></bdo>
                                                                    1. <option id="rub96"><p id="rub96"><tr id="rub96"></tr></p></option>

                                                                        <bdo id="rub96"></bdo>
                                                                        1. <track id="rub96"></track>
                                                                          1. <track id="rub96"></track>
                                                                                <bdo id="rub96"></bdo>
                                                                                <option id="rub96"></option>

                                                                                    1. <track id="rub96"><span id="rub96"></span></track>

                                                                                        <option id="rub96"></option>

                                                                                        1. 
                                                                                          
                                                                                            <option id="rub96"><span id="rub96"></span></option>
                                                                                            <bdo id="rub96"><address id="rub96"></address></bdo>
                                                                                            <option id="rub96"><source id="rub96"></source></option>
                                                                                              <nobr id="rub96"><address id="rub96"></address></nobr>
                                                                                            1. <nobr id="rub96"><optgroup id="rub96"><big id="rub96"></big></optgroup></nobr>
                                                                                              <track id="rub96"></track>

                                                                                              <nobr id="rub96"><optgroup id="rub96"></optgroup></nobr>
                                                                                                <nobr id="rub96"><optgroup id="rub96"></optgroup></nobr>

                                                                                                <bdo id="rub96"></bdo>

                                                                                                  1. <track id="rub96"><div id="rub96"></div></track>
                                                                                                    <nobr id="rub96"><optgroup id="rub96"></optgroup></nobr>

                                                                                                        <nobr id="rub96"><address id="rub96"><big id="rub96"></big></address></nobr>
                                                                                                      1. <menuitem id="rub96"><strong id="rub96"><menu id="rub96"></menu></strong></menuitem>
                                                                                                        <dl id="rub96"><source id="rub96"><tr id="rub96"></tr></source></dl>
                                                                                                        1. <tbody id="rub96"><div id="rub96"></div></tbody>
                                                                                                          1. <bdo id="rub96"><optgroup id="rub96"></optgroup></bdo>
                                                                                                          2. <bdo id="rub96"><dfn id="rub96"><dd id="rub96"></dd></dfn></bdo>
                                                                                                            1. <option id="rub96"><source id="rub96"></source></option>
                                                                                                            2. <bdo id="rub96"></bdo>

                                                                                                                <p id="rub96"><tr id="rub96"></tr></p>
                                                                                                              1. <tbody id="rub96"></tbody>

                                                                                                                <bdo id="rub96"></bdo>

                                                                                                              2. <option id="rub96"><source id="rub96"></source></option>

                                                                                                                <bdo id="rub96"><optgroup id="rub96"><dd id="rub96"></dd></optgroup></bdo>
                                                                                                                  <track id="rub96"></track>

                                                                                                                    <bdo id="rub96"></bdo>
                                                                                                                  1. <option id="rub96"><p id="rub96"><tr id="rub96"></tr></p></option>

                                                                                                                      <bdo id="rub96"></bdo>
                                                                                                                      1. <track id="rub96"></track>
                                                                                                                        1. <track id="rub96"></track>
                                                                                                                              <bdo id="rub96"></bdo>
                                                                                                                              <option id="rub96"></option>

                                                                                                                                  1. <track id="rub96"><span id="rub96"></span></track>

                                                                                                                                      <option id="rub96"></option>

                                                                                                                                      1. 
                                                                                                                                        
                                                                                                                                          <option id="rub96"><span id="rub96"></span></option>
                                                                                                                                          <bdo id="rub96"><address id="rub96"></address></bdo>
                                                                                                                                          <option id="rub96"><source id="rub96"></source></option>
                                                                                                                                            <nobr id="rub96"><address id="rub96"></address></nobr>
                                                                                                                                          1. <nobr id="rub96"><optgroup id="rub96"><big id="rub96"></big></optgroup></nobr>
                                                                                                                                            <track id="rub96"></track>

                                                                                                                                            <nobr id="rub96"><optgroup id="rub96"></optgroup></nobr>
                                                                                                                                            1. 时时缩水软件安卓 三地的开奖号码走势图 五分彩计划 皇恩平台 广东快乐十分计划在线 十大时时彩正规平台 河南新快赢481走势 最准的特马网站免费白小姐 四川时时地址 下载大彩鲸 经网黑龙江时时 四川快乐12推荐群 福彩3d开机号走势图牛胆杀码 江苏快三助手快彩 快乐12中奖概率 新疆时时开奖结果网址 中国老时时