几款模板引擎的性能对比

参评的几款模板引擎为:
  • XMLTemplate(简称XT)
  • Velocity(简称VT)
  • CommonTemplate(简称CT)
  • FreeMarker(简称FT)
  • Smarty4j(简称ST)
  • 直接的java代码



性能评测考虑以下几个方面:变量输出/循环/分支,这三大类调用构成了普通模板80%以上的功能。
测试方法为双层循环,输出的中间体是一个空的不执行任何操作的Writer类,
尽可能的减少模板外的性能影响因素,基本的逻辑伪代码描述如下:
Java代码 复制代码   收藏代码
  1. for (int i = 0; i < outerTime; i++) {   
  2.   for (int j = 0; j < innerTime; j++) {   
  3.     testXMLTemplate();   
  4.   }   
  5.   for (int j = 0; j < innerTime; j++) {   
  6.     testVelocityTemplate();   
  7.   }   
  8.   for (int j = 0; j < innerTime; j++) {   
  9.     testCommonTemplate();   
  10.   }   
  11.   for (int j = 0; j < innerTime; j++) {   
  12.     testFreeMarker();   
  13.   }   
  14.   for (int j = 0; j < innerTime; j++) {   
  15.     testSmarty4j();   
  16.   }   
  17.   for (int j = 0; j < innerTime; j++) {   
  18.     testJavaCode();   
  19.   }   
  20. }  


第一步,测试循环输出ascii码表,各模板引擎文件为

XT:asciitable.xhtml
Java代码 复制代码   收藏代码
  1. <div xmlns:c="http://www.xidea.org/ns/template/core">   
  2.   <h1>${name}</h1>   
  3.   <table border="${border}">   
  4.     <tr>   
  5.       <th>&#160;</th>   
  6.       <c:for var="cell" items="${data}">   
  7.       <th>${cell}</th>   
  8.       </c:for>   
  9.     </tr>   
  10.     <c:for var="row" items="${data}">   
  11.     <tr>   
  12.         <th>${row}</th>   
  13.         <c:for var="cell" items="${data}">   
  14.           <td><c:out value="&amp;#x"/>${row}${cell};</td>   
  15.         </c:for>   
  16.     </tr>   
  17.     </c:for>   
  18.   </table>   
  19. </div>  


VT:asciitable.vm
Java代码 复制代码   收藏代码
  1. <div>   
  2. <h1>${name}</h1>   
  3. <table border="${border}">   
  4.  <tr>   
  5.   <th>&#160;</th>   
  6. #foreach($cell in $data)   
  7.   <th>${cell}</th>   
  8. #end   
  9.  </tr>   
  10. #foreach($row in $data)   
  11.  <tr>   
  12.   <th>${row}</th>   
  13. #foreach($cell in $data )   
  14.   <td>&#x${row}${cell};</td>   
  15. #end   
  16.  </tr>   
  17. #end   
  18. </table>   
  19. </div>  


CT:asciitable.ct
Java代码 复制代码   收藏代码
  1. <div>   
  2. <h1>${name}</h1>   
  3. <table border="${border}">   
  4.  <tr>   
  5.   <th>&#160;</th>   
  6. $for{cell:data}   
  7.   <th>${cell}</th>   
  8. $end   
  9.  </tr>   
  10. $for{row:data}   
  11.  <tr>   
  12.   <th>${row}</th>   
  13. $for{cell:data}   
  14.   <td>&#x${row}${cell};</td>   
  15. $end   
  16.  </tr>   
  17. $end   
  18. </table>   
  19. </div>  


FT:asciitable.ftl
Java代码 复制代码   收藏代码
  1. <div>   
  2. <h1>${name}</h1>   
  3. <table border="${border}">   
  4.  <tr>   
  5.   <th>&#160;</th>   
  6. <#list data as cell>   
  7.   <th>${cell}</th>   
  8. </#list>   
  9.  </tr>   
  10. <#list data as row>   
  11.  <tr>   
  12.   <th>${row}</th>   
  13. <#list data as cell>   
  14.   <td>&#x${row}${cell};</td>   
  15. </#list>   
  16.  </tr>   
  17. </#list>   
  18. </table>   
  19. </div>  

Java代码 复制代码   收藏代码
  1. ST:asciitable.html   
  2. <div>   
  3. <h1>{$name}</h1>   
  4. <table border="{$border}">   
  5.  <tr>   
  6.   <th>&#160;</th>   
  7. {section loop=$data name="cell"}   
  8.   <th>{$cell}</th>   
  9. {/section}   
  10.  </tr>   
  11. {section loop=$data name="row"}   
  12.  <tr>   
  13.   <th>{$row}</th>   
  14. {section loop=$data name="cell"}   
  15.   <td>&#x{$row}{$cell};</td>   
  16. {/section}   
  17.  </tr>   
  18. {/section}   
  19. </table>   
  20. </div>  


JAVA:asciitable.java
Java代码 复制代码   收藏代码
  1. package org.jside.tt;   
  2.   
  3. import java.io.Writer;   
  4. import java.util.List;   
  5. import java.util.Map;   
  6.   
  7. public class asciitable implements ICode {   
  8.   
  9.   @Override  
  10.   public void execute(Map<String, Object> context, Writer writer) throws Exception {   
  11.     List<String> data = (List<String>) context.get("data");   
  12.     String name = (String) context.get("name");   
  13.     String border = (String) context.get("border");   
  14.     writer.write("<div>\n<h1>");   
  15.     writer.write(name);   
  16.     writer.write("</h1>\n<table border=\"");   
  17.     writer.write(border);   
  18.     writer.write("\">\n\t<tr>\n\t\t<th>&#160;</th>\n");   
  19.     for (String cell : data) {   
  20.       writer.write("\t\t<th>");   
  21.       writer.write(cell);   
  22.       writer.write("</th>\n");   
  23.     }   
  24.     writer.write("\t</tr>\n");   
  25.     for (String row : data) {   
  26.       writer.write("\t<tr>\n<th>");   
  27.       writer.write(row);   
  28.       writer.write("</th>\n");   
  29.       for (String cell : data) {   
  30.         writer.write("\t\t<td>&#x");   
  31.         writer.write(row);   
  32.         writer.write(cell);   
  33.         writer.write("</td>\n");   
  34.       }   
  35.       writer.write("\t</tr>\n");   
  36.     }   
  37.     writer.write("</table>\n</div>\n");   
  38.   }   
  39.   
  40. }  


在outerTime=100与innerTime=100时,共循环10000次,平均的结果约是:

=============runing time===============
引用
xt:2149
vt:3499
ct:72254
ft:2761
st:1235
CODE:1321


第二步,在最内层的循环中多输出一个对象,测试新增输出时的性能影响,最内层的那一行改造如下:
Java代码 复制代码   收藏代码
  1. XT:   
  2. <td>${name}:<c:out value="&amp;#x"/>${row}${cell};</td>   
  3. VT:   
  4. <td>${name}:&#x${row}${cell};</td>   
  5. CT:   
  6. <td>${name}:&#x${row}${cell};</td>   
  7. FT:   
  8. <td>${name}:&#x${row}${cell};</td>   
  9. ST:   
  10. <td>{$name}:&#x{$row}{$cell};</td>   
  11. JAVA:   
  12.         writer.write("\t\t<td>");   
  13.         writer.write(name);   
  14.         writer.write(":&#x");   
  15.         writer.write(row);   
  16.         writer.write(cell);   
  17.         writer.write("</td>\n");  


在outerTime=100与innerTime=100时,共循环10000次,平均的结果约是:
=============runing time===============
引用
xt:3549
vt:4748
ct:103453
ft:4251
st:1750
CODE:1811


第三步,测试分支判断对整体性能的影响,在最内层的循环中输出前加一个分支控制,使它仅输出A-Z对应的ASCII码表,改造如下:
Java代码 复制代码   收藏代码
  1. XT:   
  2. <td><c:if test="${(row=='4' &amp;&amp; cell!='0') || (row=='5' &amp;&amp; cell&lt;'B')}"><c:out value="&amp;#x"/>${row}${cell};</c:if><c:else><c:out value="&amp;"/>nbsp;</c:else></td>   
  3. VT:   
  4. <td>#if(($row=="4" && $cell!="0") || ($row=="5" && $cell!="B" && $cell!="C" && $cell!="D" && $cell!="E" && $cell!="F"))&#x${row}${cell};#else&nbsp;#end</td>   
  5. CT:   
  6. <td>$if{(row=="4" && cell!="0") || (row=="5" && cell<"B")}&#x${row}${cell};$else{}&nbsp;$end</td>   
  7. FT:   
  8. <td><#if (row?string=="4" && cell?string!="0") || (row?string=='5' && cell?string!='B' && cell?string!='C' && cell?string!='D' && cell?string!='E' && cell?string!='F')>&#x${row}${cell};<#else>&nbsp;</#if></td>   
  9. ST:   
  10. <td>{if ($row==='4' && $cell!=='0') || ($row==='5' && $cell<'B')}&#x{$row}{$cell};{else}&nbsp;{/if}</td>   
  11. JAVA:   
  12.         writer.write("\t\t<td>");   
  13.         if ((row.equals("4") && !cell.equals("0"))   
  14.             || (row.equals("5") && cell.compareTo("B") < 0)) {   
  15.           writer.write("&#x");   
  16.           writer.write(row);   
  17.           writer.write(cell);   
  18.         } else {   
  19.           writer.write("&nbsp;");   
  20.         }   
  21.         writer.write("</td>\n");  

考虑到比较的问题,也可以对整个循环进行优化
Java代码 复制代码   收藏代码
  1. for (String row : data) {   
  2.   char cRow = row.charAt(0);   
  3.   writer.write("\t<tr>\n<th>");   
  4.   writer.write(row);   
  5.   writer.write("</th>\n");   
  6.   for (String cell : data) {   
  7.     char cCell = cell.charAt(0);   
  8.     writer.write("\t\t<td>");   
  9.     if ((cRow == '4' && cCell != '0') || (cRow == '5' && cCell < 'B')) {   
  10.       writer.write("&#x");   
  11.       writer.write(row);   
  12.       writer.write(cell);   
  13.     } else {   
  14.       writer.write("&nbsp;");   
  15.     }   
  16.     writer.write("</td>\n");   
  17.   }   
  18.   writer.write("\t</tr>\n");   
  19. }  

在outerTime=100与innerTime=100时,共循环10000次,平均的结果约是:

=============runing time===============
引用
xt:3498
vt:2422
ct:153280
ft:7124
st:1142
CODE:1027(优化后940)


结论:
ST在三种常见的模板操作中的表现均极其优秀,除了条件处理效率略低于直接书写的JAVA代码,其它情况下与直接书写JAVA代码效率完全一致,而且在三种操作中,总的执行开销差异非常小。
XT在分支的处理中考虑与JS兼容带来了额外开销,但总体性能仍然占优,只是如果需要过多的XML转义可能影响阅读
FT在分支测试中表现差的原因应该是写法不是最优的,总体来说,性能与VT不相上下
CT的表现最差,在各项操作中均比其它的引擎慢了1-2个数量级

有关的测试代码可以在
http://templatetest.googlecode.com/svn/trunk/ 获得

你可能感兴趣的:(几款模板引擎的性能对比)