几款模板引擎的性能对比

参评的几款模板引擎为:



性能评测考虑以下几个方面:变量输出/循环/分支,这三大类调用构成了普通模板80%以上的功能。
测试方法为双层循环,输出的中间体是一个空的不执行任何操作的Writer类,
尽可能的减少模板外的性能影响因素,基本的逻辑伪代码描述如下:
Java代码 复制代码 收藏代码
  1. for(inti=0;i<outerTime;i++){
  2. for(intj=0;j<innerTime;j++){
  3. testXMLTemplate();
  4. }
  5. for(intj=0;j<innerTime;j++){
  6. testVelocityTemplate();
  7. }
  8. for(intj=0;j<innerTime;j++){
  9. testCommonTemplate();
  10. }
  11. for(intj=0;j<innerTime;j++){
  12. testFreeMarker();
  13. }
  14. for(intj=0;j<innerTime;j++){
  15. testSmarty4j();
  16. }
  17. for(intj=0;j<innerTime;j++){
  18. testJavaCode();
  19. }
  20. }
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
Java代码 复制代码 收藏代码
  1. <divxmlns:c="http://www.xidea.org/ns/template/core">
  2. <h1>${name}</h1>
  3. <tableborder="${border}">
  4. <tr>
  5. <th>&#160;</th>
  6. <c:forvar="cell"items="${data}">
  7. <th>${cell}</th>
  8. </c:for>
  9. </tr>
  10. <c:forvar="row"items="${data}">
  11. <tr>
  12. <th>${row}</th>
  13. <c:forvar="cell"items="${data}">
  14. <td><c:outvalue="&amp;#x"/>${row}${cell};</td>
  15. </c:for>
  16. </tr>
  17. </c:for>
  18. </table>
  19. </div>
<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
Java代码 复制代码 收藏代码
  1. <div>
  2. <h1>${name}</h1>
  3. <tableborder="${border}">
  4. <tr>
  5. <th>&#160;</th>
  6. #foreach($cellin$data)
  7. <th>${cell}</th>
  8. #end
  9. </tr>
  10. #foreach($rowin$data)
  11. <tr>
  12. <th>${row}</th>
  13. #foreach($cellin$data)
  14. <td>&#x${row}${cell};</td>
  15. #end
  16. </tr>
  17. #end
  18. </table>
  19. </div>
<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
Java代码 复制代码 收藏代码
  1. <div>
  2. <h1>${name}</h1>
  3. <tableborder="${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>
<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
Java代码 复制代码 收藏代码
  1. <div>
  2. <h1>${name}</h1>
  3. <tableborder="${border}">
  4. <tr>
  5. <th>&#160;</th>
  6. <#listdataascell>
  7. <th>${cell}</th>
  8. </#list>
  9. </tr>
  10. <#listdataasrow>
  11. <tr>
  12. <th>${row}</th>
  13. <#listdataascell>
  14. <td>&#x${row}${cell};</td>
  15. </#list>
  16. </tr>
  17. </#list>
  18. </table>
  19. </div>
<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>

Java代码 复制代码 收藏代码
  1. ST:asciitable.html
  2. <div>
  3. <h1>{$name}</h1>
  4. <tableborder="{$border}">
  5. <tr>
  6. <th>&#160;</th>
  7. {sectionloop=$dataname="cell"}
  8. <th>{$cell}</th>
  9. {/section}
  10. </tr>
  11. {sectionloop=$dataname="row"}
  12. <tr>
  13. <th>{$row}</th>
  14. {sectionloop=$dataname="cell"}
  15. <td>&#x{$row}{$cell};</td>
  16. {/section}
  17. </tr>
  18. {/section}
  19. </table>
  20. </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
Java代码 复制代码 收藏代码
  1. packageorg.jside.tt;
  2. importjava.io.Writer;
  3. importjava.util.List;
  4. importjava.util.Map;
  5. publicclassasciitableimplementsICode{
  6. @Override
  7. publicvoidexecute(Map<String,Object>context,Writerwriter)throwsException{
  8. List<String>data=(List<String>)context.get("data");
  9. Stringname=(String)context.get("name");
  10. Stringborder=(String)context.get("border");
  11. writer.write("<div>\n<h1>");
  12. writer.write(name);
  13. writer.write("</h1>\n<tableborder=\"");
  14. writer.write(border);
  15. writer.write("\">\n\t<tr>\n\t\t<th>&#160;</th>\n");
  16. for(Stringcell:data){
  17. writer.write("\t\t<th>");
  18. writer.write(cell);
  19. writer.write("</th>\n");
  20. }
  21. writer.write("\t</tr>\n");
  22. for(Stringrow:data){
  23. writer.write("\t<tr>\n<th>");
  24. writer.write(row);
  25. writer.write("</th>\n");
  26. for(Stringcell:data){
  27. writer.write("\t\t<td>&#x");
  28. writer.write(row);
  29. writer.write(cell);
  30. writer.write("</td>\n");
  31. }
  32. writer.write("\t</tr>\n");
  33. }
  34. writer.write("</table>\n</div>\n");
  35. }
  36. }
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


第二步,在最内层的循环中多输出一个对象,测试新增输出时的性能影响,最内层的那一行改造如下:
Java代码 复制代码 收藏代码
  1. XT:
  2. <td>${name}:<c:outvalue="&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");
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码表,改造如下:
Java代码 复制代码 收藏代码
  1. XT:
  2. <td><c:iftest="${(row=='4'&amp;&amp;cell!='0')||(row=='5'&amp;&amp;cell&lt;'B')}"><c:outvalue="&amp;#x"/>${row}${cell};</c:if><c:else><c:outvalue="&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");
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");

考虑到比较的问题,也可以对整个循环进行优化
Java代码 复制代码 收藏代码
  1. for(Stringrow:data){
  2. charcRow=row.charAt(0);
  3. writer.write("\t<tr>\n<th>");
  4. writer.write(row);
  5. writer.write("</th>\n");
  6. for(Stringcell:data){
  7. charcCell=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. }
    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/ 获得
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值