• 几款Java模板引擎的性能评测


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

    以下所有测评的结果单位都是ms

    性能评测考虑以下几个方面:变量输出/循环/分支,这三大类调用构成了普通模板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
    <!-- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -->
    <div xmlns:c="#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/获得

  • 相关阅读:
    HDU 4053 or ZOJ 3541 The Last Puzzle【区间dp】【经典题】
    HDU 4053 or ZOJ 3541 The Last Puzzle【区间dp】【经典题】
    Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) 831C. Jury Marks【二分】【水题】
    Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) 831C. Jury Marks【二分】【水题】
    POJ 2955 Brackets 【区间dp】【水题】
    POJ 2955 Brackets 【区间dp】【水题】
    动手动脑2
    统计创建了多少类
    动手动脑1
    动手动脑
  • 原文地址:https://www.cnblogs.com/u0mo5/p/4132674.html
Copyright © 2020-2023  润新知