主题:几款模板引擎的性能对比

来源:互联网 发布:怎样才能成为淘宝会员 编辑:程序博客网 时间:2024/05/22 04:38

参评的几款模板引擎为:

  • XMLTemplate(简称XT)
  • Velocity(简称VT)
  • CommonTemplate(简称CT)
  • FreeMarker(简称FT)
  • Smarty4j(简称ST)
  • 直接的java代码




性能评测考虑以下几个方面:变量输出/循环/分支,这三大类调用构成了普通模板80%以上的功能。
测试方法为双层循环,输出的中间体是一个空的不执行任何操作的Writer类,
尽可能的减少模板外的性能影响因素,基本的逻辑伪代码描述如下:

for (int i = 0; i < outerTime; i++) {  for (int j = 0; j < innerTime; j++) {    testXMLTemplate();  }  for (int j = 0; j < innerTime; j++) {    testVelocityTemplate();  }  for (int j = 0; j < innerTime; j++) {    testCommonTemplate();  }  for (int j = 0; j < innerTime; j++) {    testFreeMarker();  }  for (int j = 0; j < innerTime; j++) {    testSmarty4j();  }  for (int j = 0; j < innerTime; j++) {    testJavaCode();  }}



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

XT:asciitable.xhtml

<div xmlns:c="http://www.xidea.org/ns/template/core">  <h1>${name}</h1>  <table border="${border}">    <tr>      <th>&#160;</th>      <c:for var="cell" items="${data}">      <th>${cell}</th>      </c:for>    </tr>    <c:for var="row" items="${data}">    <tr>        <th>${row}</th>        <c:for var="cell" items="${data}">          <td><c:out value="&amp;#x"/>${row}${cell};</td>        </c:for>    </tr>    </c:for>  </table></div>



VT:asciitable.vm

<div><h1>${name}</h1><table border="${border}"> <tr>  <th>&#160;</th>#foreach($cell in $data)  <th>${cell}</th>#end </tr>#foreach($row in $data) <tr>  <th>${row}</th>#foreach($cell in $data )  <td>&#x${row}${cell};</td>#end </tr>#end</table></div>



CT:asciitable.ct

<div><h1>${name}</h1><table border="${border}"> <tr>  <th>&#160;</th>$for{cell:data}  <th>${cell}</th>$end </tr>$for{row:data} <tr>  <th>${row}</th>$for{cell:data}  <td>&#x${row}${cell};</td>$end </tr>$end</table></div>



FT:asciitable.ftl

<div><h1>${name}</h1><table border="${border}"> <tr>  <th>&#160;</th><#list data as cell>  <th>${cell}</th></#list> </tr><#list data as row> <tr>  <th>${row}</th><#list data as cell>  <td>&#x${row}${cell};</td></#list> </tr></#list></table></div>

 

ST:asciitable.html<div><h1>{$name}</h1><table border="{$border}"> <tr>  <th>&#160;</th>{section loop=$data name="cell"}  <th>{$cell}</th>{/section} </tr>{section loop=$data name="row"} <tr>  <th>{$row}</th>{section loop=$data name="cell"}  <td>&#x{$row}{$cell};</td>{/section} </tr>{/section}</table></div>



JAVA:asciitable.java

package org.jside.tt;import java.io.Writer;import java.util.List;import java.util.Map;public class asciitable implements ICode {  @Override  public void execute(Map<String, Object> context, Writer writer) throws Exception {    List<String> data = (List<String>) context.get("data");    String name = (String) context.get("name");    String border = (String) context.get("border");    writer.write("<div>/n<h1>");    writer.write(name);    writer.write("</h1>/n<table border=/"");    writer.write(border);    writer.write("/">/n/t<tr>/n/t/t<th>&#160;</th>/n");    for (String cell : data) {      writer.write("/t/t<th>");      writer.write(cell);      writer.write("</th>/n");    }    writer.write("/t</tr>/n");    for (String row : data) {      writer.write("/t<tr>/n<th>");      writer.write(row);      writer.write("</th>/n");      for (String cell : data) {        writer.write("/t/t<td>&#x");        writer.write(row);        writer.write(cell);        writer.write("</td>/n");      }      writer.write("/t</tr>/n");    }    writer.write("</table>/n</div>/n");  }}



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

=============runing time===============

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



第二步,在最内层的循环中多输出一个对象,测试新增输出时的性能影响,最内层的那一行改造如下:

XT:<td>${name}:<c:out value="&amp;#x"/>${row}${cell};</td>VT:<td>${name}:&#x${row}${cell};</td>CT:<td>${name}:&#x${row}${cell};</td>FT:<td>${name}:&#x${row}${cell};</td>ST:<td>{$name}:&#x{$row}{$cell};</td>JAVA:        writer.write("/t/t<td>");        writer.write(name);        writer.write(":&#x");        writer.write(row);        writer.write(cell);        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码表,改造如下:

XT:<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>VT:<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>CT:<td>$if{(row=="4" && cell!="0") || (row=="5" && cell<"B")}&#x${row}${cell};$else{}&nbsp;$end</td>FT:<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>ST:<td>{if ($row==='4' && $cell!=='0') || ($row==='5' && $cell<'B')}&#x{$row}{$cell};{else}&nbsp;{/if}</td>JAVA:        writer.write("/t/t<td>");        if ((row.equals("4") && !cell.equals("0"))            || (row.equals("5") && cell.compareTo("B") < 0)) {          writer.write("&#x");          writer.write(row);          writer.write(cell);        } else {          writer.write("&nbsp;");        }        writer.write("</td>/n");


考虑到比较的问题,也可以对整个循环进行优化

    for (String row : data) {      char cRow = row.charAt(0);      writer.write("/t<tr>/n<th>");      writer.write(row);      writer.write("</th>/n");      for (String cell : data) {        char cCell = cell.charAt(0);        writer.write("/t/t<td>");        if ((cRow == '4' && cCell != '0') || (cRow == '5' && cCell < 'B')) {          writer.write("&#x");          writer.write(row);          writer.write(cell);        } else {          writer.write("&nbsp;");        }        writer.write("</td>/n");      }      writer.write("/t</tr>/n");    }


在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/获得