结果就是,在2台不同的机器上,ASPX:StringTemplate:NVelocity分别为1.00:8.53:1.61和1.00:7.34:1.71,StringTemplate的性能最弱,NVelocity有点接近ASPX的解析效率。测试过程中还发现,几点:
1. 对StringTemplate,不应该连续使用StringTemplateGroup太多次,每一个任务新建一个StringTemplateGroup性能要好很多
2. 之前的某些版本,连续使用同一个StringTemplateGroup对象多次获取模板,存在严重的内存泄漏问题,性能也非常差,3.2版本性能好了很多,也没有出现内存泄漏
3. StringTemplate还有一些bug,例如下面列表测试中的Dictionary、DataTable,在3.2版本下无法读取到值(3.1的版本在列表情况下可以读取到DataTable)
测试用的项目文件: 下载
测试辅助类:
测试用的页面:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Web;
using Antlr3.ST;
using Commons.Collections;
using NVelocity;
using NVelocity.App;
using NVelocity.Runtime;
public class Contact
{public string Name { get; set; }public string EMail { get; set; }public string Address { get; set; }public decimal TotalOrderAmt { get; set; }//StringTemplate不支持模板中的比较判断&#xff0c;因此在这里处理public bool IsLevel3{get{return this.TotalOrderAmt > 1000;}}public bool IsLevel2{get{return this.TotalOrderAmt <&#61; 1000 && this.TotalOrderAmt > 200;}}public bool IsLevel1{get{return this.TotalOrderAmt <&#61; 200;}}
}
public class TemplateUtil
{private static string ST_ROOT_PATH &#61; string.Empty;static TemplateUtil(){string rootDir &#61; HttpContext.Current.Server.MapPath("./st");if (rootDir.EndsWith("\\")) rootDir &#61; rootDir.Substring(0, rootDir.Length - 1);ST_ROOT_PATH &#61; rootDir;}public static void WriteTime(string title, long time){HttpContext.Current.Response.Write("
" &#43; title);long millisecondes &#61; time % 1000;long minutes &#61; time / 1000 / 60;long seconds &#61; (time - minutes * 60 * 1000) / 1000;if (minutes > 0)HttpContext.Current.Response.Write(minutes.ToString() &#43; "m, ");if (seconds > 0)HttpContext.Current.Response.Write(seconds.ToString() &#43; "s, ");HttpContext.Current.Response.Write(millisecondes.ToString() &#43; "ms");}public static long NVelocityTest(int loops){VelocityEngine engine &#61; new VelocityEngine();ExtendedProperties prop &#61; new ExtendedProperties();prop.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, HttpContext.Current.Server.MapPath("./"));prop.AddProperty(RuntimeConstants.ENCODING_DEFAULT, "utf-8");engine.Init(prop);Stopwatch sw &#61; new Stopwatch();sw.Start();for (int i &#61; 0; i
context.Put("items1", new string[] { "AAA", "BBB", "CCC" });context.Put("items2", new List
IDictionary
DataTable table &#61; new DataTable();table.Columns.Add(new DataColumn("Key", typeof(string)));table.Columns.Add(new DataColumn("Value", typeof(int)));DataRow row &#61; table.NewRow();row["Key"] &#61; "item 1";row["Value"] &#61; 111;table.Rows.Add(row);row &#61; table.NewRow();row["Key"] &#61; "item 2";row["Value"] &#61; 222;table.Rows.Add(row);context.Put("items4", table);
if (!output){StringWriter writer &#61; new StringWriter();template.Merge(context, writer);writer.Close();}elsetemplate.Merge(context, HttpContext.Current.Response.Output);}public static long StringTemplateTest(int loops){Stopwatch sw &#61; new Stopwatch();sw.Start();for (int i &#61; 0; i
StringTemplate st &#61; group.LookupTemplate("contact_list");st.SetAttribute("contacts", new List
st.SetAttribute("items1", new string[] { "AAA", "BBB", "CCC" });st.SetAttribute("items2", new List
Dictionary
DataTable table &#61; new DataTable();table.Columns.Add(new DataColumn("Key1", typeof(string)));table.Columns.Add(new DataColumn("Value1", typeof(int)));DataRow row &#61; table.NewRow();row["Key1"] &#61; "item 1";row["Value1"] &#61; 111;table.Rows.Add(row);row &#61; table.NewRow();row["Key1"] &#61; "item 2";row["Value1"] &#61; 222;table.Rows.Add(row);st.SetAttribute("items4", table);
if (!output) st.ToString();else HttpContext.Current.Response.Write(st.ToString());}public static long ASPXTest(int loops){Stopwatch sw &#61; new Stopwatch();sw.Start();for (int i &#61; 0; i
protected void Page_Load(object sender, EventArgs e)
{this.Response.Write("NVelocity: ");List
this.Response.Write("
StringTemplate: ");times &#61; new List
this.Response.Write("
ASP.NET: ");times &#61; new List
}
NVelocity模板contact-list.vm如下:
姓名: | 地址: |
Contact List
#foreach($c in $contacts)
#beforeall
姓名 | 邮箱 | 地址 | 会员等级 |
$c.set_Name("$c.name - W") $c.get_Name() | $c.EMail | $c.Address | #if($c.TotalOrderAmt>1000)钻卡会员#elseif($c.TotalOrderAmt>200)金卡会员#else Standard#end |
#nodataNo contacts found!
#end
#if($hasMessage)
#set($msg&#61;"$message
--this message was append in NVelocity.")
#end
Item List - Array
#foreach($item in $items1)
#each$item
#between,
#end
Item List - List
#foreach($item in $items2)
#each$item.ToString("yyyy-MM-dd")
#between,
#end
Item List - Dictionary
#foreach($item in $items3)
#each
{ $item.Key - $item.Value }
#between
,#end
Item List - DataTable
#foreach($item in $items4.Rows)
{ $item.Key - $item.Value }
#between
,
#end
StringTemplate模板如下:
contact_list.st
姓名: | 地址: |
$!this is a comment!$
Contact List
姓名 | 邮箱 | 地址 | 会员等级 |
$if(hasMessage)$
--this message was append in NVelocity.
$endif$
Item List - Array
$items1:{$attr$};separator&#61;","$
Item List - List
$items2:{$attr$};separator&#61;","$
Item List - Dictionary
$items3:{{ $it$ }};separator&#61;","$
Item List - DataTable
$items4.Rows:{{ $attr$ }};separator&#61;","$
$if(attr.IsLevel3)$ 钻卡会员 $endif$
$if(attr.IsLevel2)$ 金卡会员 $endif$
$if(attr.IsLevel1)$ Standard $endif$
ASPNET.aspx页面:
姓名: | &#39; /> | 地址: | &#39; /> |
Contact List
姓名 | 邮箱 | 地址 | 会员等级 |
<% this.contacts[i].Name &#61; this.contacts[i].Name &#43; " - W"; %><%&#61; this.contacts[i].Name %> | &#39;><%&#61; this.contacts[i].EMail %> | <%&#61; this.contacts[i].Address %> | <% if(this.contacts[i].TotalOrderAmt>1000){ %>钻卡会员<% }else if (this.contacts[i].TotalOrderAmt > 200){ %>金卡会员<%}else { %>Standard<% } %> |
<% if (this.hasMessage){string msg &#61; this.message &#43; "
--this message was append in NVelocity.";%>
<%} %>
Item List - Array
<% foreach(string s in this.items1){ %>
<%&#61; s %>,
<%} %>
Item List - List
<% foreach(DateTime dt in this.items2){ %>
<%&#61; dt.ToString("yyyy-MM-dd") %>,
<%} %>
Item List - Dictionary
<% foreach(System.Collections.Generic.KeyValuePair
{<%&#61; kv.Key %>-<%&#61; kv.Value.ToString() %>},
<%} %>
Item List - DataTable
<% foreach(System.Data.DataRow row in this.items4.Rows ){ %>
{<%&#61; row["key"] %>-<%&#61; row["value"]%>},
<%} %>
public string qryName;
public string qryAddress;
public IList
public bool hasMessage;
public string message;
public string[] items1;
public List
public IDictionary
public DataTable items4;
protected void Page_Load(object sender, EventArgs e)
{if (!IsPostBack){this.qryName &#61; "Ric";this.qryAddress &#61; DateTime.Now.ToString();this.hasMessage &#61; true;this.message &#61; "This is a message from the server.";this.contacts &#61; new List
}