几款Java模板引擎的性能评测
2008-12-12 08:05
363 查看
参评的几款模板引擎为:
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> </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="&#x"/>${row}${cell};</td>
</c:for>
</tr>
</c:for>
</table>
</div>
VT:asciitable.vm
<div>
<h1>${name}</h1>
<table border="${border}">
<tr>
<th> </th>
#foreach($cell in $data)
<th>${cell}</th>
#end
</tr>
#foreach($row in $data)
<tr>
<th>${row}</th>
#foreach($cell in $data )
<td>${row}${cell};</td>
#end
</tr>
#end
</table>
</div>
CT:asciitable.ct
<div>
<h1>${name}</h1>
<table border="${border}">
<tr>
<th> </th>
$for{cell:data}
<th>${cell}</th>
$end
</tr>
$for{row:data}
<tr>
<th>${row}</th>
$for{cell:data}
<td>${row}${cell};</td>
$end
</tr>
$end
</table>
</div>
FT:asciitable.ftl
<div>
<h1>${name}</h1>
<table border="${border}">
<tr>
<th> </th>
<#list data as cell>
<th>${cell}</th>
</#list>
</tr>
<#list data as row>
<tr>
<th>${row}</th>
<#list data as cell>
<td>${row}${cell};</td>
</#list>
</tr>
</#list>
</table>
</div>
ST:asciitable.html
<div>
<h1>{$name}</h1>
<table border="{$border}">
<tr>
<th> </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>{$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> </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>");
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="&#x"/>${row}${cell};</td>
VT:
<td>${name}:${row}${cell};</td>
CT:
<td>${name}:${row}${cell};</td>
FT:
<td>${name}:${row}${cell};</td>
ST:
<td>{$name}:{$row}{$cell};</td>
JAVA:
writer.write("/t/t<td>");
writer.write(name);
writer.write(":");
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' && cell!='0') || (row=='5' && cell<'B')}"><c:out value="&#x"/>${row}${cell};</c:if><c:else><c:out value="&"/>nbsp;</c:else></td>
VT:
<
4000
td>#if(($row=="4" && $cell!="0") || ($row=="5" && $cell!="B" && $cell!="C" && $cell!="D" && $cell!="E" && $cell!="F"))${row}${cell};#else #end</td>
CT:
<td>$if{(row=="4" && cell!="0") || (row=="5" && cell<"B")}${row}${cell};$else{} $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')>${row}${cell};<#else> </#if></td>
ST:
<td>{if ($row==='4' && $cell!=='0') || ($row==='5' && $cell<'B')}{$row}{$cell};{else} {/if}</td>
JAVA:
writer.write("/t/t<td>");
if ((row.equals("4") && !cell.equals("0"))
|| (row.equals("5") && cell.compareTo("B") < 0)) {
writer.write("");
writer.write(row);
writer.write(cell);
} else {
writer.write(" ");
}
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("");
writer.write(row);
writer.write(cell);
} else {
writer.write(" ");
}
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/获得
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> </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="&#x"/>${row}${cell};</td>
</c:for>
</tr>
</c:for>
</table>
</div>
VT:asciitable.vm
<div>
<h1>${name}</h1>
<table border="${border}">
<tr>
<th> </th>
#foreach($cell in $data)
<th>${cell}</th>
#end
</tr>
#foreach($row in $data)
<tr>
<th>${row}</th>
#foreach($cell in $data )
<td>${row}${cell};</td>
#end
</tr>
#end
</table>
</div>
CT:asciitable.ct
<div>
<h1>${name}</h1>
<table border="${border}">
<tr>
<th> </th>
$for{cell:data}
<th>${cell}</th>
$end
</tr>
$for{row:data}
<tr>
<th>${row}</th>
$for{cell:data}
<td>${row}${cell};</td>
$end
</tr>
$end
</table>
</div>
FT:asciitable.ftl
<div>
<h1>${name}</h1>
<table border="${border}">
<tr>
<th> </th>
<#list data as cell>
<th>${cell}</th>
</#list>
</tr>
<#list data as row>
<tr>
<th>${row}</th>
<#list data as cell>
<td>${row}${cell};</td>
</#list>
</tr>
</#list>
</table>
</div>
ST:asciitable.html
<div>
<h1>{$name}</h1>
<table border="{$border}">
<tr>
<th> </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>{$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> </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>");
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="&#x"/>${row}${cell};</td>
VT:
<td>${name}:${row}${cell};</td>
CT:
<td>${name}:${row}${cell};</td>
FT:
<td>${name}:${row}${cell};</td>
ST:
<td>{$name}:{$row}{$cell};</td>
JAVA:
writer.write("/t/t<td>");
writer.write(name);
writer.write(":");
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' && cell!='0') || (row=='5' && cell<'B')}"><c:out value="&#x"/>${row}${cell};</c:if><c:else><c:out value="&"/>nbsp;</c:else></td>
VT:
<
4000
td>#if(($row=="4" && $cell!="0") || ($row=="5" && $cell!="B" && $cell!="C" && $cell!="D" && $cell!="E" && $cell!="F"))${row}${cell};#else #end</td>
CT:
<td>$if{(row=="4" && cell!="0") || (row=="5" && cell<"B")}${row}${cell};$else{} $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')>${row}${cell};<#else> </#if></td>
ST:
<td>{if ($row==='4' && $cell!=='0') || ($row==='5' && $cell<'B')}{$row}{$cell};{else} {/if}</td>
JAVA:
writer.write("/t/t<td>");
if ((row.equals("4") && !cell.equals("0"))
|| (row.equals("5") && cell.compareTo("B") < 0)) {
writer.write("");
writer.write(row);
writer.write(cell);
} else {
writer.write(" ");
}
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("");
writer.write(row);
writer.write(cell);
} else {
writer.write(" ");
}
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/获得
相关文章推荐
- 几款Java模板引擎的性能评测
- 几款模板引擎的性能对比
- java项目——提升网站性能之java模板引擎beetl
- 主题:几款模板引擎的性能对比
- 几款模板引擎的性能对比
- 学习记录--Beetl2.4 Java新一代的模板引擎【01】
- Play framework模板引擎扩展对象JavaExtensions
- Play framework模板引擎扩展对象JavaExtensions
- Java HotSpot性能引擎的体系结构
- 一种基于java语言的模板引擎velocity的使用
- Java HotSpot性能引擎的体系结构
- Java HotSpot 性能引擎架构
- Java几款性能分析工具的对比
- 全面超越 Velocity 的全新一代 Java 模板引擎 jetbrick-template 1.0.2 正式版发布。
- 【java模板引擎】-beetl
- NVelocity是Java模板引擎Velocity的.Net版本
- Java模板引擎 HTTL
- Java几款性能分析工具的对比
- Java模板引擎Velocity基本语法
- Velocity基于java的模板引擎(template engine)