<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

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

        Fel是最近javaeye比較火的關鍵詞,這是由網友lotusyu開發的一個高性能的EL,從作者給出的數據來看,性能非常優異,跟前段時間溫少開源的Simple EL有的一拼。首先要說,這是個好現象,國內的開源項目越來越多,可以看出開發者的水平是越來越高了,比如我最近還看到有人開源的類似kestel的輕量級MQ——fqueue也非常不錯,有興趣可以看下我的分析《fqueue初步分析》。

        進入正文,本文是嘗試分析下Fel的實現原理,以及優缺點和aviator——我自己開源的EL之間的簡單比較。

        Fel的實現原理跟Simple EL是類似,都是使用template生成中間代碼——也就是普通的java代碼,然后利用javac編譯成class,最后運行,當然,這個過程都是動 態的。JDK6已經引入了編譯API,在此之前的版本可以調用sun的類來編譯,因為javac其實就是用java實現的。回到Fel里 面,FelCompiler15就是用 com.sun.tools.javac.Main來編譯,而FelCompiler16用標準的javax.tools.JavaCompiler來編譯的。

        文法和語法解釋這塊是使用antlr這個parse generator生成的,這塊不多說,有興趣可以看下antlr,整體一個運行的過程是這樣:

        expression string -> antlr -> AST -> comiple -> java source template -> java class -> Expression 

        這個思路我在實現aviator之前就想過,但是后來考慮到API需要用的sun獨有的類,而且要求classpath必須有tools.jar這個依賴包,就放棄了這個思路,還是采用ASM生成字節碼的方式。題外,velocity的優化可以采用這個思路,我們有這么一個項目是這么做的,也準備開源了。

     

        看看Fel生成的中間代碼,例如a+b這樣的一個簡單的表達式,假設我一開始不知道a和b的類型,編譯是這樣:

        FelEngine fel = new FelEngineImpl();  
        Expression exp 
    =  fel.compile("a+b"null); 

        我稍微改了下FEL的源碼,讓它打印中間生成的java代碼,a+b生成的中間結果為:

        package com.greenpineyu.fel.compile;  
          
        
    import com.greenpineyu.fel.common.NumberUtil;  
        
    import com.greenpineyu.fel.Expression;  
        
    import com.greenpineyu.fel.context.FelContext;  
        
    import org.apache.commons.lang.ObjectUtils;  
        
    import org.apache.commons.lang.StringUtils;  
          
        
    public class Fel_0  implements Expression{  
          
            
    public Object eval(FelContext context) {  
                java.lang.Object var_1 
    = (java.lang.Object)context.get("b");   //b  
                java.lang.Object var_0 = (java.lang.Object)context.get("a");   //a  
                return (ObjectUtils.toString(var_0))+(ObjectUtils.toString(var_1));  
            }  
        } 

         可見,FEL對表達式解析和解釋后,利用template生成這么一個普通的java類,而a和b都從context中獲取并轉化為Object類型,這里沒有做任何判斷就直接認為a和b是要做字符串相加,然后拼接字符串并返回。

     

         問題出來了,因為沒有在編譯的時候傳入context(我們這里是null),FEL會將a和b的類型默認都為java.lang.Object,a+b解釋為字符串拼接。但是運行的時候,我完全可以傳入a和b都為數字,那么結果就非常詭異了:

         FelEngine fel = new FelEngineImpl();  
          
        Expression exp 
    = fel.compile("a+b"null);  
        Map
    <String, Object> env=new HashMap<String, Object>();  
        env.put(
    "a"1);  
        env.put(
    "b"3.14);  
        System.out.println(exp.eval(
    new MapContext(env))); 

    輸出:

        13.14 

        1+3.14的結果,作為字符串拼接就是13.14,而不是我們想要的4.14。如果將表達式換成a*b,就完全運行不了

        com.greenpineyu.fel.exception.CompileException: package com.greenpineyu.fel.compile;  
          
        
    import com.greenpineyu.fel.common.NumberUtil;  
        
    import com.greenpineyu.fel.Expression;  
        
    import com.greenpineyu.fel.context.FelContext;  
        
    import org.apache.commons.lang.ObjectUtils;  
        
    import org.apache.commons.lang.StringUtils;  
          
        
    public class Fel_0  implements Expression{  
          
            
    public Object eval(FelContext context) {  
                java.lang.Object var_1 
    = (java.lang.Object)context.get("b");   //b  
                java.lang.Object var_0 = (java.lang.Object)context.get("a");   //a  
                return (var_0)*(var_1);  
            }  
        }  
          
        [Fel_0.java:
    14: 運算符 * 不能應用于 java.lang.Object,java.lang.Object]  
            at com.greenpineyu.fel.compile.FelCompiler16.compileToClass(FelCompiler16.java:
    113)  
            at com.greenpineyu.fel.compile.FelCompiler16.compile(FelCompiler16.java:
    87)  
            at com.greenpineyu.fel.compile.CompileService.compile(CompileService.java:
    66)  
            at com.greenpineyu.fel.FelEngineImpl.compile(FelEngineImpl.java:
    62)  
            at TEst.main(TEst.java:
    14)  
        Exception in thread 
    "main" java.lang.NullPointerException  
            at TEst.main(TEst.java:
    18

     

        這個問題對于Simple EL同樣存在,如果沒有在編譯的時候能確定變量類型,這無法生成正確的中間代碼,導致運行時出錯,并且有可能造成非常詭異的bug。

     

        這個問題的本質是因為Fel和Simple EL沒有自己的類型系統,他們都是直接使用java的類型的系統,并且必須在編譯的時候確定變量類型,才能生成高效和正確的代碼,我們可以將它們稱為“強類型的EL“。

     

        現在讓我們在編譯的時候給a和b加上類型,看看生成的中間代碼:

        FelEngine fel = new FelEngineImpl();  
        fel.getContext().set(
    "a"1);  
        fel.getContext().set(
    "b"3.14);  
        Expression exp 
    = fel.compile("a+b"null);  
        Map
    <String, Object> env = new HashMap<String, Object>();  
        env.put(
    "a"1);  
        env.put(
    "b"3.14);  
        System.out.println(exp.eval(
    new MapContext(env))); 

        查看中間代碼:

        package com.greenpineyu.fel.compile;  
          
        
    import com.greenpineyu.fel.common.NumberUtil;  
        
    import com.greenpineyu.fel.Expression;  
        
    import com.greenpineyu.fel.context.FelContext;  
        
    import org.apache.commons.lang.ObjectUtils;  
        
    import org.apache.commons.lang.StringUtils;  
          
        
    public class Fel_0  implements Expression{  
          
            
    public Object eval(FelContext context) {  
                
    double var_1 = ((java.lang.Number)context.get("b")).doubleValue();   //b  
                double var_0 = ((java.lang.Number)context.get("a")).doubleValue();   //a  
                return (var_0)+(var_1);  
            }  
        } 

    可以看到這次將a和b都強制轉為double類型了,做數值相加,結果也正確了:

        4.140000000000001 

        Simple EL我沒看過代碼,這里猜測它的實現也應該是類似的,也應該有同樣的問題。

        相比來說,aviator這是一個弱類型的EL,在編譯的時候不對變量類型做任何假設,而是在運行時做類型判斷和自動轉化。過去提過,我給aviator的定位是一個介于EL和script之間的東西,它有自己的類型系統。 例如,3這個數字,在java里可能是long,int,short,byte,而aviator統一為AviatorLong這個類型。為了在這兩個類 型之間做適配,就需要做很多的判斷和box,unbox操作。這些判斷和轉化都是運行時進行的,因此aviator沒有辦法做到Fel這樣的高效,但是已 經做到至少跟groovy這樣的弱類型腳本語言一個級別,也超過了JXEL這樣的純解釋EL,具體可以看這個性能測試。

     

       強類型還是弱類型,這是一個選擇問題,如果你能在運行前就確定變量的類型,那么使用Fel應該可以達到或者接近于原生java執行的效率,但是失去了靈活性;如果你無法確定變量類型,則只能采用弱類型的EL。

     

       EL涌現的越來越多,這個現象有點類似消息中間件領域,越來越多面向特定領域的輕量級MQ的出現,而不是原來那種大而笨重的通用MQ大行其道,一方面是互 聯網應用的發展,需求不是通用系統能夠滿足的,另一方面我認為也是開發者素質的提高,大家都能造適合自己的輪子。從EL這方面來說,我也認為會有越來越多 特定于領域的,優點和缺點一樣鮮明的EL出現,它們包含設計者自己的目標和口味,選擇很多,就看取舍。

    posted @ 2011-09-17 12:52 dennis 閱讀(9954) | 評論 (5)編輯 收藏


        fqueue是國產的一個類似memcacheq,kestrel這樣的支持memcached協議的輕量級開源MQ。它的項目主頁:
    http://code.google.com/p/fqueue/downloads/list,介紹和特點都可以看主頁,我就不廢話了。

        今天老大提到, co了源碼看了下,寫個初步分析報告。

        首先是它的存儲層,主要是一個FQueue這么一個抽象隊列,內部實現是FSQueue,也就是基于文件的FIFO隊列。這個隊列是多個文件組成的。每個文件默認大小在150M,超過即切換一個新文件來寫。讀的時候如果讀到尾部,則查找下一個文件進行讀取。數據文件名以idb為后綴,并且從編號1開始遞增,除了數據文件外,每個隊列還有個db為后綴的索引文件,記錄當前寫和讀的數據文件編號和偏移量。目錄結構大概是這樣:
        --fqueue
            --fqueuedata_1.idb
            --fqueuedata_2.idb
            --……
            --icqueue.db

        文件的存儲比較有特色,采用MappedByteBuffer做文件讀寫,MappedByteBuffer是java nio引入的文件內存映射方案,讀寫性能極高,但是也有一定的問題,比如說內存占用,以及數據刷入設備的不確定性和關閉問題。在fqueue中,每隔10毫秒會強制force一次buffer,將修改過的數據刷入設備。對于關閉問題,則采用那個技巧,示例代碼:
    /**
         * 關閉索引文件
         
    */
        
    public void close() {
            
    try {
                mappedByteBuffer.force();
                AccessController.doPrivileged(
    new PrivilegedAction<Object>() {
                    
    public Object run() {
                        
    try {
                            Method getCleanerMethod 
    = mappedByteBuffer.getClass().getMethod("cleaner"new Class[0]);
                            getCleanerMethod.setAccessible(
    true);
                            sun.misc.Cleaner cleaner 
    = (sun.misc.Cleaner) getCleanerMethod.invoke(mappedByteBuffer,
                                    
    new Object[0]);
                            cleaner.clean();
                        } 
    catch (Exception e) {
                            log.error(
    "close logindexy file error:", e);
                        }
                        
    return null;
                    }
                });
                fc.close();
                dbRandFile.close();
                mappedByteBuffer 
    = null;
                fc 
    = null;
                dbRandFile 
    = null;
            } 
    catch (IOException e) {
                log.error(
    "close logindex file error:", e);
            }
        }

        利用反射,并且使用了sun特有的類,不具有可移植性。MappedByteBuffer還有一個問題是map的代價比較高,可能在切換文件的時候fqueue會有一定程度的阻塞現象。

        存儲的性能,我在我的機器測試了下,似乎沒有作者宣稱的那么高,我的機器是5400轉的普通SATA盤,寫入1K數據的平均QPS在8000左右。我估計fqueue的性能跟磁盤有很大關系,如果使用15000轉的SAS盤應該能有很大改觀。

        網絡層直接使用了jmemcached的實現,jmemcached是一個java實現的memcached,通常用于單元測試之類。看情況fqueue也支持memcached的二進制協議了。網絡框架使用了netty3,這些就不多說了。自己看都明白。額外提一下,作者做的單元測試使用了xmemcached,咔咔,廣而告之。

        總體來說fqueue是一個整體上很清爽和輕量級的MQ實現,適合一些特定的場景,至于性能,我們下周準備做個壓測,到時候再談吧。

    posted @ 2011-09-16 20:10 dennis 閱讀(9236) | 評論 (7)編輯 收藏

        開源的java memcached client—— xmemcached發布1.3.4版本,主要改進如下:

     

    1、修復一個相對嚴重的bug,在解析二進制協議時如果遇到從服務端返回的錯誤信息,會導致連接異常斷開;如果你沒有使用binary協議,不會遇到此問題。建議使用xmemcached并且使用二進制協議的朋友升級到此版本。

    2、允許XMemcachedClientFactoryBean配置opTimeout選項。

    3、添加RoundRobinMemcachedSessionLocator,輪詢的連接選擇器,僅用于kestrel或者memcacheq集群,這些應用都不要求同一個key要保存在固定的服務器上,而僅是作為集群分擔負載。

    4、KetamaMemcachedSessionLocator添加額外選項,允許配置是否兼容 nginx-upstream-consistent,這個是網友 wolfg1969貢獻的patch。如果要使得xmc的一致性哈希算法兼容nginx-upstream-consistent,只要設置cwNginxUpstreamConsistent為true即可,示范代碼:

        MemcachedClientBuilder builder = new XMemcachedClientBuilder(  
                        AddrUtil.getAddresses(servers));  
          
        builder.setSessionLocator(
    new KetamaMemcachedSessionLocator(  
                        
    true)); 

    5、修復bug,包括issue 132 , issue 142 , issue 133 , issue 139 , issue 142 , issue 145 ,issue 150等。

     

    如果你使用maven,只要簡單升級版本即可: 

      <dependency>  
             
    <groupId>com.googlecode.xmemcached</groupId>  
             
    <artifactId>xmemcached</artifactId>  
             
    <version>1.3.4</version>  
        
    </dependency> 

    下載地址:

    http://code.google.com/p/xmemcached/downloads/list

    posted @ 2011-09-08 18:55 dennis 閱讀(3285) | 評論 (3)編輯 收藏


        這篇blog遲到了很久,本來是想寫另一個跟網絡相關bug的查找過程,偷偷懶,寫下最近印象比較深刻的bug。這個bug是我的同事水寒最終定位到的。
        前幾個月同事報告稱有一個線上MQ集群會同一時間拋出ArrayIndexOutOfBoundsException這個異常,也就是數組越界。查看源碼,除去一些無關緊要的細節大概是這樣子:
    public class ConnectionSelector{
        
    private AtomicInteger sets=new AtomicInteger(0);

       
    public void selectConnection(List<Connection> connList){
              
    if(connList==null){
                    
    return null;
               }
              
    final int size = connList.size();
                
    if (size == 0) {
                    
    return null;
                }
               
    return connList.get(sets.incrementAndGet() % size);
    }

       }

        很顯然,這里的本意是實現一個輪詢的連接選擇器,返回一個選中的連接。使用AtomicInteger遞增并對鏈表大小取模,返回結果索引位置的連接。異常拋出的位置就是我代碼中標紅的位置。

        顯然,這里有兩種可能,一種情況下是說在執行那一行代碼的時候,connList的大小縮小了(也就是說連接可能被其他線程移出),那么導致取模的結果越界。另一種可能是取模的結果本身確實超過了列表范圍。

        第一種情況是完全可能的,因為服務器的連接可能隨時斷開或者重連,但是這種情況相對非常少見,因此我們這里并沒有對這個選擇過程做同步,主要是從性能的角度出發,偶爾的失敗可以接受。很遺憾的是,我被我的思維慣性誤導了,從來沒有懷疑過第二種情況,總是認為是不是真的連接恰巧斷開導致這個異常,但是卻無法解釋這個異常發生后就一直錯誤下去,無法自行恢復。
        為什么說思維慣性誤導呢?這里的問題其實是負數取模的問題,對一個負數進行取模,結果會是正數還是負數?答案是結果因語言而異。
        我很早以前在使用Ruby的時候做過測試,負數取模結果為正數,例如在irb里嘗試下:
    >> -1000%3
    => 2
    >> -2001%4
    => 3

        這個印象持續至今,在clojure里結果也是這樣子:
    Clojure 1.2.1
    user
    => (mod -1000 3)
    2
    user
    => (mod -2001 4)
    3

        可以再試試python:
    Python 2.7.1 (r271:86832, Jun 16 201116:59:05
    [GCC 
    4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
    Type 
    "help""copyright""credits" or "license" for more information.
    >>> -10000%3
    2
    >>> -2001%4
    3

        這三種語言的結果完全一致,結果都為正數。這個慣性思維延續到java卻不成立了,可惜我根本沒做測試,讓我們試下:
       public static void main(final String[] args) {
            System.out.println(
    -1000 % 3);
            System.out.println(
    -2001 % 4);
        }

    打印結果為:
    -1
    -1

        果然,在java里負數取模的結果為負數,而不是我習慣性地認為是正數。因此最終的定位到的原因就是sets這個變量遞增超過Integer.MAX_VALUE后越界變成負數了,取模的結果為負數,導致拋出數組越界的異常,這也解釋了為什么同一個集群都在同一時間出問題,因為這個集群內的機器啟動時間相鄰并且調用這個方法次數相對平均。修正問題很簡單,加個Math.abs就好。

        Update:加個abs是不夠的,因為Math.abs的javadoc提醒了:
    Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative.

        也就是說對Integer.MIN_VALUE做abs結果仍然是負數。盡管在這個場景中失敗一次可以接受,但是最好的辦法還是回復中steven提到的抵消符號位的做法:
    (sets.incrementAndGet() & 0x7FFFFFFF% size
       
        這個問題更詳細的討論后來我找到這篇博客,作者討論幾種語言和計算器的這個問題的結果,給出了一些結論。不過我覺的這個結論可能也不是那么可靠,特別是對c/c++來說,很大程度上應該還是依賴于實現,最可靠的辦法還是強制結果為正。

        這個bug的幾個教訓:
    1、首先是第一次出現的時候沒有引起足夠重視,重啟解決問題后沒有深究。有句玩笑話:99%的程序問題都可以通過重啟解決。但是事實上問題仍然存在,該發生的終究還會發生。不管你信不信,它就是發生了,這是一個奇跡。
    2、注意大腦的思維慣性,經驗主義和教條主義都不可取。最近在讀一本好書《暗時間》,大腦誤導我們的手段可是多種多樣。
    3、最后就是這個負數取模的結果因語言而異,不要依賴于特定實現。
       

    posted @ 2011-09-02 00:02 dennis 閱讀(4138) | 評論 (5)編輯 收藏

        沒有耐心看經過的請直接拉到末尾看slide列表。

        這個聚會是由江宏首先提議的,我參與協助。目的是讓長三角地區對clojure語言感興趣,或者正在使用的朋友當面認識和交流一下。會議的組織過程一波三折,首先是會議地點本來定在了上海google辦公室,但是后來google那邊又說不讓過去,我再聯系了原來淘寶網的同事火狐,經過他的努力和幫助,最終將地點確定在了上海大眾點評。要感謝大眾點評網和火狐的幫助,不然這次活動估計就黃了。會議的日期選定也比較偶然,跟七夕撞在了一天,并且8月6號這天說臺風“梅花”要在江浙一帶登陸,上海要刮多少級多少級的大風,加上我和杭州的幾個朋友過去要坐高鐵,那心里就七上八下了,搞不好就要被“掩埋”了。我們還開玩笑說最好買火車中段車廂的票為妙。

        8月6日一早,和同在淘寶的楊冬,加上兩位做ROR的朋友一起出發,天氣沒有想象的糟糕,高鐵一個小時就到了,轉地鐵到大眾點評網大概也才中午12點左右。打了電話給火狐,一起吃了飯然后就直奔大眾點評網。大眾點評網的前臺大廳裝修也是非常熟悉的橙色,很意外周6有很多人,后來才知道是在搞招聘會和培訓。這時候,江宏他們也從昆山趕到了,火狐幫我們定的會議室很大,足夠容納20號人左右。陸續有人達到,到約定的1點的時候,我記的是來了大概11還是12個人,還有幾個朋友在路上,因此我們決定推遲到1點半再開始。最終來的人估計有15個以上,估計報名的都來了。

        1點半正式開始,首先是我來講《clojure概覽》這個topic,主要是一個clojure語言的介紹。這個是我上周開始準備的,在去年《clojure的魅力》的基礎上做了刪減和增加,聽取江宏的意見增加了示例和引子。上周也在我們的團隊講過一次。輕車熟路,也為了給后面的topic留出時間,我講的比較快,大概40分鐘就結束了。

        接下來是孫寧(sunng87)講《clojure開發的生命周期管理》,我對clojure的周邊工具并不熟悉,趁機更好地了解了很多 clojure開發過程中用到的工具和資料,推薦對clojure開發感興趣的朋友看下。嘗試了下clooj,比我預期的要好,遺憾的是還沒有語法高亮,推薦初學clojure的朋友可以嘗試下這個輕量級的IDE。目前最好的clojure IDE還是idea里的La Clojure插件。最后孫寧順便廣告了下lein-control插件,這是孫寧構建的一個clojure-control的lein插件,他還貢獻了一個類似python里fabric的clojure DSL實現,讓clojure-control更易用。

        接下來是江宏介紹他們開發trakrapp.com這個純clojure實現的網站中使用的技術,以及遇到的問題和經驗。這個網站基于compojure這個框架實現的,前端采用backbone.js,后端是MongoDB和postgresql,可以說都是非常“新潮”的技術。他在談遇到問題的時候,提到clojure的stack trace又長又丑,這一點深有體會,clojure的異常堆棧包含了java和clojure的,整個調用鏈相對較長,非常不利于問題的排查,不知道后續clojure會不會對這一點做出改進。

        接下來是林晴介紹他們一個用scala實現的類似domino的企業OA系統,不過他這個例子給我的感覺更多是發揮了mongodb的schema free的特點,沒有體現出使用scala的好處來。我對scala的觀點一直很明確,scala想做JVM上的c++,從個人角度不喜歡這種多范式的語言,并且語法不符合我的胃口,特別是類型系統這塊特別復雜,我怕我在寫scala的時候還要參考一本厚厚的reference,這不是我想要的。而clojure的核心就非常小,相對符合我的期望。

        作為東道主的火狐介紹了大眾點評網的新架構以及他們從.net往java遷移的經驗,他們的新架構也是做服務化和中心化,對于.net和java平臺來說,遷移更多是從人力成本和一些其他因素決定的,當然,遷移最重要的還是要有公司高層的全力支持,特別重要的一點是如何讓老員工也參與這個過程。因為老員工對現有系統和業務最熟悉,將他們排除在外閉門造車是注定要失敗的。

        最后是同樣來自昆山文石的吳哲介紹如何在半天內實現一個HTML 5的游戲,他介紹的processing.js非常有趣,processing本身是一門編程語言,有人將它移植到了js上,可以直接在支持html5上瀏覽器展現,效果相當cool。巧合的是我在回去后的第二天去書店的時候,竟然在某個角落看到《processing互動編程藝術》這本書,買了下來準備了解下。做數據圖形化的同學可以關注下。

        總體來講,這次聚會的效果超過我的預期,在超強臺風的陰影下和七夕愛情的感召下還有這么多人趕過來,作為組織者之一非常感動。并且topic講座也讓我學習了一些東西,最重要的是當面認識了一些網上交流過的朋友,給我印象深刻的是看起來非常老成的孫寧,完全不像個85后。還有個印象深刻的細節是現場的5,6臺mbp,這里面還是因為有同學是在搞ROR的因素。

        最后,給下slide的鏈接如下:

    1,我的《clojure概覽》,源碼在github上。
    2,孫寧的《Clojure開發的生命周期管理》,lein-controlclojure-control。
    3,江宏的《Clojure web development》,他們開發的網站
    4,吳哲的《How to build a html5 game in half a day
    5,火狐的《大眾點評網新架構
    6,cn-clojure主頁
     

    posted @ 2011-08-09 14:09 dennis 閱讀(7587) | 評論 (3)編輯 收藏

        最近看了篇在google reader里分享非常多的文章,我表示很無語,文章在這里,題目是《Peter Norvig:編程語言的選擇并不重要》。簡單來講這文章就是鼓吹python的,然后舉了很多例子說python描述算法比Lisp容易。這個無需多說,圖靈模型本來就比lambda演算更適合描述算法。

        我想說的是,文中明明提了,Peter norvig說的是:
    就更一般意義上的編程而言,在Google和其他地方,我認為語言的選擇并不如其他方面的選擇那么重要:如果你有了正確的總體架構、正確的程序員團隊、正確的開發過程(能夠快速開發、持續改善),那么很多語言都能勝任;但如果以上的東西你沒有,那無論選擇什么語言,你都會陷入一團糟。

       這句話的意思很明顯,在google或者其他什么地方,編程語言的選擇,比之正確的架構,正確的團隊以及正確的開發過程,對最終任務的完成影響不是那么大。但并非所謂"編程語言的選擇不重要“,這種斷章取義的題目除了吸引眼球外,沒有任何益處。
        很多編程語言都可以勝任你要完成的編程任務,你完全可以用C去寫CGI,用匯編去寫消息中間件,只要你有正確的架構,正確的團隊和開發過程,你應該總能完成任務。但是選擇適當的編程語言可以讓你事半功倍,更少的代碼,更高的開發效率。從ROR以及動態語言的流行來看,選擇編程語言,真的很重要。

        除非你的規模達到google的程度,性能意味著美元,一秒的優化意味著成千甚至上億的dollar的時候,也許你可以說下編程語言的選擇不重要。

        最后,我還想鄙視下分享這篇文章的大爺們,你們真的看了文章嗎?還只是沖著這標題,急急忙忙地獻寶式地分享了?咱們淡定點行不?

    posted @ 2011-08-06 23:51 dennis 閱讀(6009) | 評論 (10)編輯 收藏

    轉自 http://hjiang.net/archives/484

    Clojure-CN要組織周期性的線下技術交流活動了。如果你熱愛程序設計的相關技術,并且住在長三角一帶,歡迎來參與活動。只要填一下這個調查表就可以:
     http://www.diaochapai.com/survey548296

    更多:
        關注我的blog的朋友應該都知道我這一年都一直在關注clojure這門語言,后來還搞了個cn-clojure的google group。hjiang的公司在使用clojure做商業項目,他們公司可能是國內唯一在使用clojure的商業團體,他上周跟我提起想搞這么個活動,促進對clojure學習和使用的交流,并且不局限在clojure語言本身。今年其實給自己一個目標也是去嘗試推動一些事情,我對clojure純粹是技術上的興趣,未來也不排除去找一份專職寫clojure的工作,如果你或者他(她)對clojure語言(或者函數式語言)感興趣,歡迎來參加這次聚會,填寫下這個調查表: http://www.diaochapai.com/survey548296。

        我們在調查完成后統計下大家的興趣點和地理分布,最后決定在哪里舉辦,以及確定talk列表和聚會形式等。

        我還申請了一個域名 http://cnlojure.org,在github上建了個page,這件事的進展會放到這個網頁上。

    posted @ 2011-07-27 16:19 dennis 閱讀(3772) | 評論 (1)編輯 收藏


        格式化源碼是很常見的需求,emacs有個indent-region函數用于格式化選定的代碼,前提是你處在某個非text mode下,如c-mode或者java-mode之類。如果要格式化整個文件,你需要先選定整個文件(C-x-h),然后調用indent-region(或者 C-M-\ )。兩個命令總是麻煩,我們可以定義個函數搞定這一切,并綁定在一個特定鍵上,實現一鍵格式化:

    ;;格式化整個文件函數
    (defun indent
    -whole ()
      (interactive)
      (indent
    -region (point-min) (point-max))
      (message 
    "format successfully"))
    ;;綁定到F7鍵
    (global
    -set-key [f7] 'indent-whole)

        將這段代碼添加到你的emacs配置文件(~/.emacs),重啟emacs,以后格式化源碼都可以用F7一鍵搞定。

    posted @ 2011-07-26 11:24 dennis 閱讀(9506) | 評論 (4)編輯 收藏


    1.選定宿主語言,最好選用元編程能力強悍的語言作為宿主語言。
    2.確定DSL的樣子,讓腦袋空白,不去考慮任何實現問題,純粹思考你想要實現的dsl是什么樣子
    3.用你想要的DSL寫一個最基本的例子,只包括最基本的功能。
    4.開始實現DSL,盡快讓你的DSL例子以dirty and quick的方式跑起來。
    5.寫更多DSL的例子,慢慢包括你想要的所有功能,并一一實現,在這個過程中你可能改變DSL的樣子,原來模糊的東西漸漸清楚。
    6.大功告成,review你的代碼并添加自動化測試,將代碼中dirty和bad smell的部分一一剔除。
    7.讓你的DSL接受實際應用的考驗吧。

    posted @ 2011-07-25 19:30 dennis 閱讀(3533) | 評論 (1)編輯 收藏

    update: Allow passing command line arguments to task now.

    1.What is clojure-control?

        The idea came from node-control.
        Define clusters and tasks for system administration or code deployment, then execute them on one or many remote machines.
        Clojure-control depends only on OpenSSH and clojure on the local control machine.Remote machines simply need a standard sshd daemon.

    2.Quick example

    Get the current date from the two machines listed in the 'mycluster'  config with a single command:

         (ns samples
         (:use [control.core :only [task cluster scp ssh begin]]))
         ;;define clusters
         (cluster :mycluster
                     :clients [
                                   { :host 
    "a.domain.com" :user "alogin"}
                                   { :host 
    "b.domain.com" :user "blogin"}
                                 ])
         ;;define tasks
         (task :date 
    "Get date"
                  []
                  (ssh 
    "date"))
        ;;start running
        (begin)

        If saved in a file named "controls.clj",run with   

    java -cp clojure.jar:clojure-contrib.jar:control-0.1-SNAPSHOT.jar clojure.main controls.clj mycluster date

        Each machine execute "date" command ,and the output form the remote machine is printed to the console.Exmaple console output

     

        Performing mycluster
        Performing date 
    for a.domain.com
        a.domain.com:ssh: date
        a.domain.com:stdout: Sun Jul 
    24 19:14:09 CST 2011
        a.domain.com:exit: 
    0
        Performing date 
    for b.domain.com
        b.domain.com:ssh: date
        b.domain.com:stdout: Sun Jul 
    24 19:14:09 CST 2011
        b.domain.com:exit: 
    0

        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.


    3.How to scp files?
        Let's define a new task named deploy

      (task :deploy "scp files to remote machines"
            []
            (scp (
    "release1.tar.gz" "release2.tar.gz""/home/alogin/"))

        Then it will copy release1.tar.gz and release2.tar.gz to remote machine's /home/alogin directory.

    4.Where is it?

        It's on github,https://github.com/killme2008/clojure-control

        Any suggestion or bug reports welcomed.

    posted @ 2011-07-24 21:48 dennis 閱讀(3174) | 評論 (0)編輯 收藏

    僅列出標題
    共56頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 
    主站蜘蛛池模板: 免费一本色道久久一区| 亚洲丝袜美腿视频| 免费无码A片一区二三区| 成人免费ā片在线观看| 亚洲а∨精品天堂在线| 亚洲午夜精品国产电影在线观看| 亚洲人成色77777| av无码东京热亚洲男人的天堂| 国产91免费视频| 久久精品免费视频观看| 国产亚洲精品免费视频播放| 麻豆一区二区三区蜜桃免费| 亚洲欧洲日韩极速播放| 亚洲精品**中文毛片| 亚洲国产精品自在线一区二区| 亚洲精品午夜无码专区| 亚洲一区二区精品视频| www.亚洲色图| www.亚洲精品| 亚洲人午夜射精精品日韩| 免费播放特黄特色毛片| 四虎影视精品永久免费| 国产精品视_精品国产免费 | 久久精品亚洲男人的天堂| 国产一区二区三区免费看| 全免费a级毛片免费看无码| 国产麻豆视频免费观看| 国产无人区码卡二卡三卡免费| 国产精品久久免费| 日韩免费一区二区三区在线 | 亚洲人色大成年网站在线观看| 久久精品国产精品亚洲毛片| 久久久久亚洲精品天堂| 亚洲天堂一区在线| 国产成人亚洲精品| 亚洲AV无码一区二区三区久久精品 | 在线观看亚洲AV每日更新无码| 亚洲人成网站色在线观看| 亚洲人av高清无码| 国产精品亚洲精品日韩动图| 国产成人va亚洲电影|