閱讀949 返回首頁    go 王者榮耀


輕量級高性能的表達式求值器——aviator發布2.0

    aviator是一個輕量級的、高性能的Java表達式求值器,主要應用在如工作流引擎節點條件判斷、MQ中的消息過濾以及某些特定的業務場景。

    自從上次發布1.0後,還發過1.01版本,不過都沒怎麼宣傳。這次發布一個2.0的裏程碑版本,主要改進如下:


1、完整支持位運算符,與java完全一致。位預算符對實現bit set之類的需求還是非常必須的。

2、性能優化,平均性能提升100%,函數調用性能提升200%,最新的與groovy和JEXL的性能測試看這裏

https://code.google.com/p/aviator/wiki/Performance

3、添加了新函數,包括long、double、str用於類型轉換,添加了string.indexOf函數。

4、完善了用戶手冊,更新性能測試。

 

下載地址:  https://code.google.com/p/aviator/downloads/list

項目主頁:  https://code.google.com/p/aviator/

用戶指南:  https://code.google.com/p/aviator/w/list

性能報告:  https://code.google.com/p/aviator/wiki/Performance

源碼:          https://github.com/killme2008/aviator

 

Maven引用(感謝許老大的幫助):

    <dependency>
            
<groupId>com.googlecode.aviator</groupId>
            
<artifactId>aviator</artifactId>
                        
<version>2.0</version>
    
</dependency>

     這個項目目前用在我們的MQ產品中做消息過濾,也有幾個公司外的用戶告訴我他們也在用,不過估計不會很多。有這種需求的場景還是比較少的。這個項目實際上是為我們的MQ定製的,我主要想做到這麼幾點:

(1)控製用戶能夠使用的函數,不允許調用任何不受控製的函數。

(2)輕量級,不需要嵌入groovy這麼大的腳本引擎,我們隻需要一個剪裁過的表達式語法即可。

(3)高性能,最終的性能在某些場景比groovy略差,但是已經非常接近。

(4)易於擴展,可以容易地添加函數擴展功能。語法相對固定。

(5)函數的調用避免使用反射。因此沒使用dot運算符的函數調用方式,而是更類似c語言和lua語言的函數調用風格。函數是一等公民,seq庫的風格很符合我的喜好。

  seq這概念來自clojure,我將實現了java.util.Collection接口的類和數組都稱為seq集合,可以統一使用seq庫操作。例如假設我有個list:

        Map<String, Object> env = new HashMap<String, Object>();
        ArrayList
<Integer> list = new ArrayList<Integer>();
        list.add(
3);
        list.add(
100);
        list.add(
-100);
        env.put(
"list", list);

   可以做這麼幾個事情,度量大小:
count(list)
   判斷元素是否存在:
include(list,3)
   過濾元素,返回大於0的元素組成的seq:
filter(list,seq.gt(0))
   對集合裏的元素求和,應用reduce:
reduce(list,+,0)
   遍曆集合元素並打印:
map(list,println)
   最後,你還可以排序:
sort(list)

    這些函數類似FP裏的高階函數,使用起來還是非常爽的。

    對函數調用的優化,其實隻幹了一個事情,原來函數調用我是將所有參數收集到一個list裏麵,然後再轉成數組元素交給AviatorFunction調用。這裏創建了兩個臨時對象:list和數組。這其實是沒有必要的,我隻要在AviatorFunction裏定義一係列重載方法,如:
   public AviatorObject call(Map<String, Object> env);


    
public AviatorObject call(Map<String, Object> env, AviatorObject arg1);


    
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2);


    
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3);

    


   就不需要收集參數,而是直接invokeinterface調用AviatorFunction相應的重載方法即可。我看到在JRuby和Clojure裏的方法調用都這樣幹的。過去的思路走岔了。最終也不需要區分內部的method和外部的function,統一為一個對象即可,進一步減少了對象創建的開銷。

文章轉自莊周夢蝶  ,原文發布時間 2011-07-13

最後更新:2017-05-18 20:31:30

  上一篇:go  基於Consul的分布式鎖實現
  下一篇:go  找bug記(1)