莊周夢(mèng)蝶

          生活、程序、未來(lái)
             :: 首頁(yè) ::  ::  :: 聚合  :: 管理

          2012年7月10日


          很久沒(méi)有更新博客,沒(méi)想到更新是搬遷公告。這個(gè)博客累計(jì)的訪問(wèn)量突破百萬(wàn),是我建立的時(shí)候完全沒(méi)有想過(guò)的事情。博客對(duì)我來(lái)說(shuō)更多是記錄、記憶的地方,我時(shí)常因?yàn)橄氩黄鹉硞€(gè)東西,來(lái)翻自己的博客,查找舊知,發(fā)現(xiàn)新知。閱讀很多人的博客,也是我跟蹤、學(xué)習(xí)新知的主要方式。雖然微博興起,不過(guò)博客作為更系統(tǒng)性的記錄的地方,不會(huì)過(guò)時(shí)。

          非常感謝blogjava提供這么優(yōu)秀的平臺(tái)。只是我今年給自己的一個(gè)目標(biāo)是建立自己的博客,因此現(xiàn)在要搬遷,加上其實(shí)現(xiàn)在也寫的少,其實(shí)搬遷不搬遷,意義也不大了。算是一個(gè)通告,有興趣的可以訂閱我的新博客,沒(méi)興趣的請(qǐng)自行略過(guò),謝謝大家。

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

          新博客的第一篇記憶是《Leiningen教程中文版》,從現(xiàn)在開(kāi)始,這個(gè)博客將不再發(fā)布任何新的文章,已有的也不會(huì)刪除,部分可能會(huì)導(dǎo)到我的知識(shí)庫(kù)上去。

          最后,祝福blogjava越辦越好。

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

          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| 編輯 收藏

          很久沒(méi)寫博客,一是工作忙,二是沒(méi)有太多的事情可說(shuō)。

          最近在公司大佬的支持下,建立了一個(gè)Clojure語(yǔ)言中文方面的博客和問(wèn)答網(wǎng)站,歡迎任何對(duì)Clojure這門基于JVM之上的函數(shù)式語(yǔ)言感興趣的童鞋貢獻(xiàn)原創(chuàng)文章或者資料,申請(qǐng)帳號(hào)請(qǐng)看這里。

          博客地址:  http://blog.clojure.cn/
          問(wèn)答網(wǎng)站:  http://ask.clojure.cn/

          歡迎轉(zhuǎn)發(fā)和注冊(cè)使用,謝謝。

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

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

          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 閱讀(9514) | 評(píng)論 (0)編輯 收藏


              Clojure的一大優(yōu)點(diǎn)就是跟Java語(yǔ)言的完美配合,Clojure和Java之間可以相互調(diào)用,Clojure可以天然地使用Java平臺(tái)上的豐富資源。在Clojure里調(diào)用一個(gè)類的方法很簡(jiǎn)單,利用dot操作符:

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

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

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

              我們打開(kāi)*warn-on-reflection*選項(xiàng),當(dāng)有反射的時(shí)候告警:

          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
             
              問(wèn)題出現(xiàn)了,由于函數(shù)substr里沒(méi)有任何關(guān)于參數(shù)s的類型信息,為了調(diào)用s的substring方法,必須使用反射來(lái)調(diào)用,clojure編譯器也警告我們調(diào)用substring沒(méi)辦法解析,只能通過(guò)反射調(diào)用。眾所周知,反射調(diào)用是個(gè)相對(duì)昂貴的操作(對(duì)比于普通的方法調(diào)用有)。這一切都是因?yàn)閏lojure本身是弱類型的語(yǔ)言,對(duì)參數(shù)或者返回值你不需要聲明類型而直接使用,Clojure會(huì)自動(dòng)處理類型的轉(zhuǎn)換和調(diào)用。ps.在leiningen里啟用反射警告很簡(jiǎn)單,在project.clj里設(shè)置:

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

              問(wèn)題1,什么時(shí)候應(yīng)該為參數(shù)添加type hint呢?我的觀點(diǎn)是,在任何為target object添加type hint的地方,都應(yīng)該相應(yīng)地為參數(shù)添加type hint,除非你事先不知道參數(shù)的類型。為什么呢?因?yàn)閏lojure查找類方法的順序是這樣:

          1.從String類里查找出所有參數(shù)個(gè)數(shù)為2并且名稱為substring方法
          2.遍歷第一步里查找出來(lái)的Method,如果你有設(shè)置參數(shù)的type hint,則
          查找最匹配參數(shù)類型的Method;否則,如果第一步查找出來(lái)的Method就一個(gè),直接使用這個(gè)Method,相反就認(rèn)為沒(méi)有找到對(duì)應(yīng)的Method。
          3.如果第二步?jīng)]有找到Method,使用反射調(diào)用;否則根據(jù)該Method元信息生成調(diào)用字節(jié)碼。

             因此,如果substring方法的兩個(gè)參數(shù)版本剛好就一個(gè),方法參數(shù)有沒(méi)有type hint都沒(méi)有關(guān)系(有了錯(cuò)誤的type hint反而促使反射的發(fā)生),我們都會(huì)找到這個(gè)唯一的方法;但是如果目標(biāo)方法的有多個(gè)重載方法并且參數(shù)相同,而只是參數(shù)類型不同(Java里是允許方法的參數(shù)類型重載的,Clojure只允許函數(shù)的參數(shù)個(gè)數(shù)重載),那么如果沒(méi)有方法參數(shù)的type hint,Clojure編譯器仍然無(wú)法找到合適的調(diào)用方法,而只能通過(guò)反射。
             
             看一個(gè)例子,定義get-bytes方法調(diào)用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都沒(méi)有設(shè)置type hint,有反射警告;第二次,s設(shè)置了type hint,但是還是有反射警告。原因就在于String.getBytes有兩個(gè)重載方法,參數(shù)個(gè)數(shù)都是一個(gè),但是接收不同的參數(shù)類型,一個(gè)是String的charset名稱,一個(gè)Charset對(duì)象。如果我們明確地知道這里charset是字符串,那么還可以為charset添加type hint:
          user=> (defn get-bytes [^String s ^String charset] (.getBytes s charset))
          #'user/get-bytes
             
              這次才真正的沒(méi)有警告了??偨Y(jié):在設(shè)置type hint的時(shí)候,不要只考慮被調(diào)用的target object,也要考慮調(diào)用的方法參數(shù)。

              問(wèn)題2:什么時(shí)候應(yīng)該添加tag元數(shù)據(jù)呢?理論上,在任何你明確知道返回類型的地方都應(yīng)該添加tag,但是這不是教條,如果一個(gè)偶爾被調(diào)用的方法是無(wú)需這樣做的。這一點(diǎn)只對(duì)寫庫(kù)的童鞋要特別注意。

              Type hint的原理在上文已經(jīng)大概描述了下,具體到clojure源碼級(jí)別,請(qǐng)參考clojure.lang.Compiler.InstanceMethodExpr類的構(gòu)造函數(shù)和emit方法。最后,附送是否使用type hint生成substr函數(shù)的字節(jié)碼之間的差異對(duì)比:
          未使用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


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

              參考:

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

          主站蜘蛛池模板: 黎川县| 营口市| 平遥县| 屏南县| 色达县| 高邮市| 石狮市| 嘉义县| 兴安县| 陆川县| 南陵县| 岑溪市| 新野县| 娄底市| 监利县| 高州市| 长顺县| 怀化市| 双峰县| 沧州市| 乐东| 辉县市| 平陆县| 顺平县| 岫岩| 偃师市| 锦州市| 沂水县| 临漳县| 临朐县| 图木舒克市| 嘉义县| 宜兴市| 五家渠市| 纳雍县| 阜新市| 永新县| 金川县| 华阴市| 阳原县| 岚皋县|