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

简介: 参评的几款模板引擎为:XMLTemplate(简称XT)Velocity(简称VT)CommonTemplate(简称CT)FreeMarker(简称FT)Smarty4j(简称ST)直接的java代码 以下所有测评的结果单位都是ms 性能评测考虑以下几个方面:变量输出/循环/分支,这三大类调用构成了普通模板80%以上的功能。

参评的几款模板引擎为:
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/获得

目录
相关文章
|
2月前
|
缓存 算法 Java
Java 实现的局域网管控软件的性能调优
局域网管控软件在企业网络管理中至关重要,但随着网络规模扩大和功能需求增加,其性能可能受影响。文章分析了数据处理效率低下、网络通信延迟和资源占用过高等性能瓶颈,并提出了使用缓存、优化算法、NIO库及合理管理线程池等调优措施,最终通过性能测试验证了优化效果,显著提升了软件性能。
38 1
|
24天前
|
XML Java 数据库连接
性能提升秘籍:如何高效使用Java连接池管理数据库连接
在Java应用中,数据库连接管理至关重要。随着访问量增加,频繁创建和关闭连接会影响性能。为此,Java连接池技术应运而生,如HikariCP。本文通过代码示例介绍如何引入HikariCP依赖、配置连接池参数及使用连接池高效管理数据库连接,提升系统性能。
53 5
|
1月前
|
Java 数据库连接 数据库
优化之路:Java连接池技术助力数据库性能飞跃
在Java应用开发中,数据库操作常成为性能瓶颈。频繁的数据库连接建立和断开增加了系统开销,导致性能下降。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接,显著减少连接开销,提升系统性能。文章详细介绍了连接池的优势、选择标准、使用方法及优化策略,帮助开发者实现数据库性能的飞跃。
30 4
|
1月前
|
Java 数据库连接 数据库
深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能
在Java应用开发中,数据库操作常成为性能瓶颈。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能。文章介绍了连接池的优势、选择和使用方法,以及优化配置的技巧。
30 1
|
2月前
|
存储 缓存 算法
提高 Java 数组性能的方法
【10月更文挑战第19天】深入探讨了提高 Java 数组性能的多种方法。通过合理运用这些策略,我们可以在处理数组时获得更好的性能表现,提升程序的运行效率。
33 2
|
3月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
459 37
|
2月前
|
缓存 Java 数据库连接
使用 NCache 将 Java 微服务扩展到极致性能
使用 NCache 将 Java 微服务扩展到极致性能
31 8
|
3月前
|
缓存 Java 应用服务中间件
Java虚拟线程探究与性能解析
本文主要介绍了阿里云在Java-虚拟-线程任务中的新进展和技术细节。
117 23
|
3月前
|
监控 算法 Java
深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
|
3月前
|
安全 Java API
【性能与安全的双重飞跃】JDK 22外部函数与内存API:JNI的继任者,引领Java新潮流!
【9月更文挑战第7天】JDK 22外部函数与内存API的发布,标志着Java在性能与安全性方面实现了双重飞跃。作为JNI的继任者,这一新特性不仅简化了Java与本地代码的交互过程,还提升了程序的性能和安全性。我们有理由相信,在外部函数与内存API的引领下,Java将开启一个全新的编程时代,为开发者们带来更加高效、更加安全的编程体验。让我们共同期待Java在未来的辉煌成就!
72 11