1. 程式人生 > >jsp與模板引擎效能

jsp與模板引擎效能

在討論模板引擎的效能之前必須先明確幾個問題:
1. 在同等優化條件下,java原生程式碼最快。
2. jsp在只採用java指令碼編寫的情況下,可以認為與java原生程式碼的效能相當,仍然是在同等優化條件下。
3. 編譯效能可以不考慮,因為都是編譯一次,多次執行,對執行期沒有影響。


有些模板引擎的效能優於jsp,這個只是由於對比的jsp容器做的優化較少,而模板引擎做了大量優化。
例如tomcat的jsper引擎,優化做的比較少,在模板引擎中很常見的優化手段在jsper中都沒有做,所以一些模板引擎的效能超越tomcat的jsp引擎並不奇怪。
如果採用同等的優化條件,無論是什麼模板引擎,效能最多能與只採用java指令碼的jsp效能相當,不可能超越。除非這個模板引擎生成的位元組碼比jdk自帶的編譯器生成的位元組碼效率高。


jsp技術的幾個常規優化點:
1. 把字串常量定義為靜態char陣列,這個優化效果是很明顯的。以下示例程式碼是jsp引擎編譯之後的java程式碼,例如:
    out.write("Hello World !");
    優化成:
    out.write(_jsp_string_1, 0, _jsp_string_1.length);
    private static final String _jsp_string_1 = "Hello World !".toCharArray();
    這樣做的好處:1,節省記憶體,減少記憶體碎片,減輕gc壓力;2,減少記憶體申請;3,減少方法呼叫。
    tomcat的jsp引擎並沒有採用這樣的優化,resin的jsp引擎使用了這樣的方式。


2. 拆分大方法為小方法。
    JVM在執行到熱點方法的時候會編譯為原生代碼執行,效能更高,但是如果方法體過大,則JIT不會生效。
    tomcat對每個標籤都會編譯為一個方法,而resin不會。
    我沒有看過tomcat的原始碼是如何實現的,但是我覺的這種方式是有限制的:被編譯的方法不能使用java指令碼。


3. 儘可能減少呼叫el引擎。例如: ${userName}這個el表示式就可以不呼叫el引擎,僅僅輸出pageContext.getAttribute("userName")就可以了。


4. 使用fastJstl模式,例如: <c:if test="${user.age > 18}">Hello !</c:if>,可以編譯為:
    if(elEngine.getBoolean("user.age > 18")) {
        out.wirte("Hello !");
    }
    而不是編譯成IfTag,然後呼叫一堆的IfTag的方法。
    tomcat對任何標籤都會編譯出標籤物件,並且按照標籤的生命週期呼叫執行,而resin則採用了fastJstl模式,並且預設是開啟狀態。不知道tomcat的jsper引擎是否支援該模式。


影響jsp頁面效能的幾個關鍵點:
1. el表示式,可以說對jsp效能影響最大的就是el表示式了。
    el表示式一般是解釋執行,而且大量使用反射,java的反射效能很低,與原生的java程式碼相比,效能相差好幾個數量級。
    如果頁面上有相當多的el表示式,效能差一點都不奇怪。


2. 標籤
    jstl的生命週期決定了一個簡單的方法呼叫一旦使用標籤來實現,最終要執行的指令數立即幾倍甚至幾十倍的增加。而且一個標籤在初始化的時候很可能也存在el呼叫。


3. 能用el標籤輸出的不要用標籤輸出,例如: ${user.name}優於<c:out value="${user.name}"/>,後者比前者還要多執行一次標籤建立和呼叫。
   不過這個例子有些jsp引擎會優化為:out.write(elEngine.getString("user.name")); 與直接寫el表示式的效果一樣。


除去以上兩點,如果一個jsp頁面只採用java指令碼編寫,並且jsp引擎做適度的優化,那麼jsp無疑是效能最好的。
但是像tomcat這種很流行的jsp容器在jsp的效能上優化的並不多。而目前很多java的模板引擎做很很多效能優化,甚至很多效能都超過了tomcat的jsp引擎。
例如HTTL,從實現原理上看,上面提到的優化手段全都採用了,而且它是無反射呼叫的,效能與原生程式碼相當。
我所知道的httl所採用的優化手段:
1. 無反射呼叫。jsp除非採用原生程式碼編寫,否則很難做到無反射。
2. 字串常量直接編譯為byte陣列,這個優化更徹底。jsp裡面不可能採用這個優化手段,因為api介面JspWriter是字元流。
httl所採用的優化手段都是在jsp裡面很難做到或者由於api的限制沒法做的,所以httl的效能可以認為是超過jsp的。當然這不是說jsp效能不好,而是說httl可以採用的優化手段比jsp多,而且像tomcat這種連一些常規的優化都沒做。
唯一不爽的是httl的語法不是我喜歡的型別,這是個人喜好問題,拋去這些,httl是我見過的效能最好的。


模板引擎的效能測試
一般的效能測試最好在單執行緒模式下進行。併發下的測試唯一有用的是測試是否存線上程安全的問題,高併發下測試結果幾乎沒有參考價值,尤其是那些把執行緒數都壓的不夠用了,測試結果就更不可信了。因為當大量執行緒都在等待執行機會的時候,討論那個執行更快完全沒有意義。
例如隨便用任何一個模板引擎寫一個複雜的頁面,然後用原生程式碼寫個hello world在高併發下測試一下就知道了,原來效能差不多!例子誇張了點,但大概意思差不多。