马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
一 简介
1、AScript
AScript是一个开源的C#动态脚本解析执行引擎,支持自定义语法,支持扩展多种脚本语言(目前已支持C#/Python3/SQL/JavaScript/Lua五种语言),支持表明执行和编译执行两种执行模式,而且支持编译缓存,以适配不同场景下对性能的要求。
目前官方最新版本:1.6.0
开源地址:
- https://gitee.com/rockey627/AScript
- https://github.com/rockey627/AScript
2、DynamicExpresso
DynamicExpresso是一个开源的,用.NET Standard 2.0编写的简单c#语句的表明器,将表达式转换为.NET lambda表达式或委托来执行c#语句。
目前官方最新版本:2.19.3
开源地址:https://github.com/dynamicexpresso/DynamicExpresso
二 性能测试
使用Benchmark工具举行性能基准测试,测试情况:- BenchmarkDotNet v0.14.0, Windows 11 (10.0.22621.4317/22H2/2022Update/SunValley2)
- AMD Ryzen 7 7840H with Radeon 780M Graphics, 1 CPU, 16 logical and 8 physical cores
- .NET SDK 9.0.316
- [Host] : .NET 6.0.36 (6.0.3624.51421), X64 RyuJIT AVX2
- DefaultJob : .NET 6.0.36 (6.0.3624.51421), X64 RyuJIT AVX2
复制代码 安装nuget包:- install-package AScript
- install-package DynamicExpresso.Core
复制代码 1、常量表达式
- 1 // 待测试表达式
- 2 private static readonly string s = "100 * (5 + 5) * (6-2)";
- 3 // 用于测试结果比较,确保测试执行结果是正确的
- 4 private static readonly int r = 100 * (5 + 5) * (6 - 2);
复制代码 分3个测试场景:
1)表明执行
DynamicExpresso不支持表明执行,对AScript的表明执行模式举行测试,以举行综合评价,测试代码如下:- 1 [Benchmark]
- 2 public void AScript1()
- 3 {
- 4 var script = new Script();
- 5 var result = script.Eval<int>(s);
- 6 if (result != r) throw new Exception("result error");
- 7 }
复制代码 2)编译执行- 1 [Benchmark]
- 2 public void AScript2_Compile()
- 3 {
- 4 var script = new Script();
- 5 var result = script.Eval<int>(s, ECompileMode.All);
- 6 if (result != r) throw new Exception("result error");
- 7 }
- 8
- 9 [Benchmark]
- 10 public void Expresso2()
- 11 {
- 12 var interpreter = new DynamicExpresso.Interpreter();
- 13 var result = interpreter.Eval<int>(s);
- 14 if (result != r) throw new Exception("result error");
- 15 }
复制代码 3)编译缓存
此为通用缓存场景,根据字符串表达式缓存编译生成的委托,提高整体性能。AScript已内置缓存功能,DynamicExpresso需手动添加缓存逻辑。- 1 private static Script _Script3;
- 2
- 3 [Benchmark]
- 4 public void AScript3_Cache()
- 5 {
- 6 if (_Script3 == null)
- 7 {
- 8 _Script3 = new Script();
- 9 }
- 10 var result = _Script3.Eval<int>(s, -1);
- 11 if (result != r) throw new Exception("result error");
- 12 }
- 13
- 14 private static readonly ConcurrentDictionary<string, Delegate> _DynamicExpresso3Dict = new ConcurrentDictionary<string, Delegate>();
- 15
- 16 [Benchmark]
- 17 public void Expresso3()
- 18 {
- 19 string key = s;
- 20 if (!_DynamicExpresso3Dict.TryGetValue(key, out var func))
- 21 {
- 22 var interpreter = new DynamicExpresso.Interpreter();
- 23 func = interpreter.ParseAsDelegate<Func<int>>(s);
- 24 _DynamicExpresso3Dict[key] = func;
- 25 }
- 26 var result = ((Func<int>)func)();
- 27 if (result != r) throw new Exception("result error");
- 28 }
复制代码 测试效果如下:
小结:
- 表明执行模式对比编译执行模式有肯定优势,因为编译生成委托本钱比力大。
- 编译执行模式,AScript比DynamicExpresso性能高。
- 编译缓存模式,DynamicExpresso性能略高于AScript。
2、变量表达式
- 1 // 待测试表达式,包含a、b、c三个变量
- 2 private static readonly string s = "a * (b + 5) * (c-2)";
- 3 // 用于测试结果比较,确保测试执行结果是正确的
- 4 private static readonly int r = 100 * (5 + 5) * (6 - 2);
复制代码 分3个测试场景:
1)表明执行- 1 [Benchmark]
- 2 public void AScript1()
- 3 {
- 4 var script = new Script();
- 5 script.Context.SetVar("a", 100);
- 6 script.Context.SetVar("b", 5);
- 7 script.Context.SetVar("c", 6);
- 8 var result = script.Eval<int>(s);
- 9 if (result != r) throw new Exception("result error");
- 10 }
复制代码 2)编译执行- 1 [Benchmark]
- 2 public void AScript2_Compile()
- 3 {
- 4 var script = new Script();
- 5 script.Context.SetVar("a", 100);
- 6 script.Context.SetVar("b", 5);
- 7 script.Context.SetVar("c", 6);
- 8 var result = script.Eval<int>(s, ECompileMode.All);
- 9 if (result != r) throw new Exception("result error");
- 10 }
- 11
- 12 [Benchmark]
- 13 public void Expresso2()
- 14 {
- 15 var interpreter = new DynamicExpresso.Interpreter();
- 16 interpreter.SetVariable("a", 100);
- 17 interpreter.SetVariable("b", 5);
- 18 interpreter.SetVariable("c", 6);
- 19 var result = interpreter.Eval<int>(s);
- 20 if (result != r) throw new Exception("result error");
- 21 }
复制代码 3)编译缓存
DynamicExpresso编译生成委托后,如果再修改上下文中的变量值,委托执行效果不会变,不会动态从上下文获取变量,以是对DynamicExpresso的编译缓存测试没有意义。- 1 [Benchmark]
- 2 public void AScript3_Cache()
- 3 {
- 4 var script = new Script();
- 5 script.Context.SetVar("a", 100);
- 6 script.Context.SetVar("b", 5);
- 7 script.Context.SetVar("c", 6);
- 8 var result = script.Eval<int>(s, -1);
- 9 if (result != r) throw new Exception("result error");
- 10 }
复制代码 测试效果如下:
小结:AScript性能优势比力明显。
3、LINQ表达式
- 1 private static readonly List<int> _list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
- 2 // 待测试表达式
- 3 private static readonly string s = "list.Where(a => a % 2 == 0).ToList().Count";
- 4 // 用于测试结果比较,确保测试执行结果是正确的
- 5 private static readonly int r = 5;
复制代码 1)表明执行- 1 [Benchmark]
- 2 public void AScript1()
- 3 {
- 4 var script = new Script();
- 5 script.Context.SetVar("list", _list);
- 6 var result = script.Eval<int>(s);
- 7 if (result != r) throw new Exception("result error");
- 8 }
复制代码 2)编译执行
DynamicExpresso执行LINQ表达式需要开启InterpreterOptions.LambdaExpressions选项。- 1 [Benchmark]
- 2 public void AScript2_Compile()
- 3 {
- 4 var script = new Script();
- 5 script.Context.SetVar("list", _list);
- 6 var result = script.Eval<int>(s, ECompileMode.All);
- 7 if (result != r) throw new Exception("result error");
- 8 }
- 9
- 10 [Benchmark]
- 11 public void Expresso2()
- 12 {
- 13 var options = InterpreterOptions.Default | InterpreterOptions.LambdaExpressions;
- 14 var interpreter = new DynamicExpresso.Interpreter(options);
- 15 interpreter.SetVariable("list", _list);
- 16 var result = interpreter.Eval<int>(s);
- 17 if (result != r) throw new Exception("result error");
- 18 }
复制代码 3)编译缓存- 1 [Benchmark]
- 2 public void AScript3_Cache()
- 3 {
- 4 var script = new Script();
- 5 script.Context.SetVar("list", _list);
- 6 var result = script.Eval<int>(s, -1);
- 7 if (result != r) throw new Exception("result error");
- 8 }
复制代码 测试效果如下:
小结:AScript性能优于DynamicExpresso
4、生成委托
- 1 [Benchmark]
- 2 public void AScript1()
- 3 {
- 4 var script = new Script();
- 5 var func = script.Compile<int, int, int>("a + b", "a", "b");
- 6 var result = func(4, 6);
- 7 if (result != 10) throw new Exception("result error");
- 8 }
- 9
- 10 [Benchmark]
- 11 public void Expresso1()
- 12 {
- 13 var interpreter = new DynamicExpresso.Interpreter();
- 14 var func = interpreter.ParseAsDelegate<Func<int, int, int>>("a + b", "a", "b");
- 15 var result = func(4, 6);
- 16 if (result != 10) throw new Exception("result error");
- 17 }
复制代码 测试效果如下:
小结:AScript性能高。
5、生成Lambda
仅测试生成lambda性能,不做计算。- 1 [Benchmark]
- 2 public void AScript1()
- 3 {
- 4 var script = new Script();
- 5 Expression<Func<int, int, int>> lambda = script.Lambda<int, int, int>("a + b", "a", "b");
- 6 if (lambda == null) throw new Exception("result error");
- 7 }
- 8
- 9 [Benchmark]
- 10 public void Expresso1()
- 11 {
- 12 var interpreter = new DynamicExpresso.Interpreter();
- 13 Expression<Func<int, int, int>> lambda = interpreter.ParseAsExpression<Func<int, int, int>>("a + b", "a", "b");
- 14 if (lambda == null) throw new Exception("result error");
- 15 }
复制代码 测试效果如下:
小结:AScript性能高。
三 总结
1)AScript支持多语句,DynamicExpresso不支持,通过多次调用Eval方式来实现多语句;
2)AScript比DynamicExpresso性能高,内存占用低;
3)AScript默认为表明执行模式,不缓存也能有较高的性能;
4)AScript内置编译缓存功能,支持缓存版本号和定时缓存,不同应用场景使用合适的缓存策略,来提高项目整体性能。
|