.net模板引擎 jntemplate v2.0 测试, 要国产,也要速度

  • A+
所属分类:.NET技术
摘要

jntemplate 是一款国产的文本解析引擎(模板引擎),最近2.0的版本进行了重构,笔者在Gihub上挑了几个模板引擎做了一个简单的小对比测试,看下国产的质量怎么样!

jntemplate 是一款国产的文本解析引擎(模板引擎),最近2.0的版本进行了重构,笔者在Gihub上挑了几个模板引擎做了一个简单的小对比测试,看下国产的质量怎么样!

环境说明:

操作系统:Windows 10.0.19041.746

CPU: Intel Xeon CPU E3-1231 v3 3.40GHz

内存:8G

.NET 框架:  net 5

测试工具:BenchmarkDotNet 0.12.1

参与测试的引擎:

JinianNet.JNTemplate 2.0.0
Mustachio 2.1.0
RazorEngineCore 2020.10.1
RazorLight 2.0.0-rc.3
Scriban 3.4.2

说明一下,Razor官方是视图引擎,不方便直接测试,所以找了二款基于Razor的第三方引擎来参与测试,其中RazorEngine因为版本太老无法支持.net 5,故选择了RazorLight 与RazorEngineCore 

以 上文件均从nuget安装。语法参照官文档编写并尽量统一。

 

测试一:输出一个变量或者属性

测试用代码:

using BenchmarkDotNet.Attributes; using JinianNet.JNTemplate; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;  namespace Test {     [MemoryDiagnoser]     public class TestVariable     {         [Benchmark]         public void RunJntemplate()         {             var template = Engine.CreateTemplate("Hello $model.Id !");             template.Set("model", new UserInfo { Id = 10, Name = "your name!" });             var value = template.Render();         }          [Benchmark]         public void RunMustachio()         {             var template = Mustachio.Parser.Parse("Hello {{Id}} !");             dynamic model = new System.Dynamic.ExpandoObject();             model.Id = 10;             model.Name = "your name!";             var value = template(model);         }          [Benchmark]         public void RunScriban()         {             var template = Scriban.Template.Parse("Hello {{Id}} !");             var value = template.Render(new UserInfo { Id = 10, Name = "your name!" });         }            [Benchmark]         public void RunRazorEngineCore()         {             //RazorEngineCore.IRazorEngineCompiledTemplate template;             var razorEngine = new RazorEngineCore.RazorEngine();             var template = razorEngine.Compile("Hello @Model.Id");             var value = template.Run(new UserInfo { Id = 10, Name = "your name!" });         }           [Benchmark]         public void RunRazorLight()         {             var engine = new RazorLight.RazorLightEngineBuilder()                 // required to have a default RazorLightProject type,                 // but not required to create a template from string.                 .UseEmbeddedResourcesProject(typeof(UserInfo))                 //.SetOperatingAssembly(typeof(UserInfo).Assembly)                 .UseMemoryCachingProvider()                 .Build();              string template = "Hello @Model.Id";             var model = new UserInfo { Id = 10, Name = "your name!" };              string result =  engine.CompileRenderStringAsync("templateKey", template, model).GetAwaiter().GetResult();         }     } } 

  

测试结果:

.net模板引擎 jntemplate v2.0 测试, 要国产,也要速度

 

这里可以看到二个razor引擎所需要的时间是最长的,这是因为它们是编译型引擎,初始运行需要进行编译,所以会占用较多时间。

不过为什么jntemplate也是编译型引擎,所占时间却最少呢?

 

测试二:测试一的代码一共运行10万次

即然一次说明不了什么,接下来我们进行第二项测试,把上面的代码各运行10万次。

测试代码:

using BenchmarkDotNet.Attributes; using JinianNet.JNTemplate; using RazorEngineCore;  using System.Collections.Concurrent;   namespace Test {     [MemoryDiagnoser]     public class TestVariableMultiple     {         private int Max = 100000;          [Benchmark]         public void RunJntemplate()         {             string text = "Hello $model.Id";             var hashCode = text.GetHashCode().ToString();             for (var i = 0; i < Max; i++)             {                 var template = JinianNet.JNTemplate.Engine.CreateTemplate(hashCode, text);                 template.Set("model", new UserInfo { Id = 10, Name = "your name!" });                 var value = template.Render();             }         }          [Benchmark]         public void RunScriban()         {             Scriban.Template template = Scriban.Template.Parse("Hello {{Id}} !");             for (var i = 0; i < Max; i++)             {                 var value = template.Render(new UserInfo { Id = 10, Name = "your name!" });             }          }          [Benchmark]         public void RunMustachio()         {             var template = Mustachio.Parser.Parse("Hello {{Id}} !");             for (var i = 0; i < Max; i++)             {                 dynamic model = new System.Dynamic.ExpandoObject();                 model.Id = 10;                 model.Name = "your name!";                 var value = template(model);             }         }          [Benchmark]         public void RunRazorEngineCore()         {             var TemplateCache = new ConcurrentDictionary<int, IRazorEngineCompiledTemplate>();             string text = "Hello @Model.Id";             int hashCode = text.GetHashCode();              for (var i = 0; i < Max; i++)             {                  IRazorEngineCompiledTemplate compiledTemplate = TemplateCache.GetOrAdd(hashCode, i =>                 {                     RazorEngine razorEngine = new RazorEngine();                     return razorEngine.Compile(text);                 });                  var value = compiledTemplate.Run(new UserInfo { Id = 10, Name = "your name!" });             }         }          [Benchmark]         public void RunRazorLight()         {             var engine = new RazorLight.RazorLightEngineBuilder()                  .UseEmbeddedResourcesProject(typeof(UserInfo))                  .UseMemoryCachingProvider()                 .Build();              string template = "Hello @Model.Id";             var model = new UserInfo { Id = 10, Name = "your name!" };             for (var i = 0; i < Max; i++)             {                 if (i==0)                 {                     string result = engine.CompileRenderStringAsync("templateKey", template, model).GetAwaiter().GetResult();                 }                 else                 {                     var cacheResult = engine.Handler.Cache.RetrieveTemplate("templateKey");                     if (cacheResult.Success)                     {                         var templatePage = cacheResult.Template.TemplatePageFactory();                         string result = engine.RenderTemplateAsync(templatePage, model).GetAwaiter().GetResult();                     }                 }             }         }     } } 

  

测试结果:

.net模板引擎 jntemplate v2.0 测试, 要国产,也要速度

 

运行10万次后,编译型引擎的速度明显占优

 

测试三:foreach 遍历10万次

测试代码:

using BenchmarkDotNet.Attributes; using JinianNet.JNTemplate; using RazorEngineCore; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;  namespace Test {     /// <summary>     /// /     /// </summary>     [MemoryDiagnoser]     public class TestForeach     {         private int[] arr;         private int max = 100000;          public TestForeach()         {             arr = new int[max];             for(var i = 0; i < max; i++)             {                 arr[i] = i;             }         }          [Benchmark]         public void RunScriban()         {             var template = Scriban.Template.Parse(@" <ul id='products'>   {{ for product in products }}     <li>{{ product }}</li>   {{ end }} </ul> ");             var result = template.Render(new { Products = arr });           }          [Benchmark]         public void RunJntemplate()         {             string text = @" <ul> $for(node in list) <li>$node</li> $end </ul> ";             var hashCode = text.GetHashCode().ToString();             var template = JinianNet.JNTemplate.Engine.CreateTemplate(hashCode, text);             template.Set("list", arr);             var value = template.Render();         }          [Benchmark]         public void RunRazorEngineCore()         {             var razorEngine = new RazorEngineCore.RazorEngine();              var TemplateCache = new ConcurrentDictionary<int, IRazorEngineCompiledTemplate>();             string text = @" <ul> @{ foreach (var item in Model) {     <li>@item</li>  } } </ul> ";              var template = razorEngine.Compile(text);             var value = template.Run(arr);         }          [Benchmark]         public void RunRazorLight()         {             var engine = new RazorLight.RazorLightEngineBuilder()                 // required to have a default RazorLightProject type,                 // but not required to create a template from string.                 .UseEmbeddedResourcesProject(typeof(UserInfo))                 //.SetOperatingAssembly(typeof(UserInfo).Assembly)                 .UseMemoryCachingProvider()                 .Build();              string text = @" <ul> @{ foreach (var item in Model) {     <li>@item</li>  } } </ul> ";              string result = engine.CompileRenderStringAsync("templateKey", text, arr).GetAwaiter().GetResult();         }     } } 

  

测试结果:

.net模板引擎 jntemplate v2.0 测试, 要国产,也要速度

 

mustachio没有找到怎么foreach的语法,这里就没测试,Scriban 支持不了这么大的数组,所以没有结果。

 

还有一些复杂的用法,今天暂时就不测了,结论我就不用说了,当然本次测试并不完整,毕竟一个引擎涉及到的地方很多,仅仅一二个用法不能代表不了全部,所以结果仅供参考。

另外mustachio功能上太简单,其实无法和其它引擎相提并论,这里只拿来只是凑个数!

 大家怎么看呢?