C#脚本引擎之AScript与DynamicExpresso对比

[复制链接]
发表于 2026-8-22 17:29:53 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一 简介

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工具举行性能基准测试,测试情况:
  1. BenchmarkDotNet v0.14.0, Windows 11 (10.0.22621.4317/22H2/2022Update/SunValley2)
  2. AMD Ryzen 7 7840H with Radeon 780M Graphics, 1 CPU, 16 logical and 8 physical cores
  3. .NET SDK 9.0.316
  4.   [Host]     : .NET 6.0.36 (6.0.3624.51421), X64 RyuJIT AVX2
  5.   DefaultJob : .NET 6.0.36 (6.0.3624.51421), X64 RyuJIT AVX2
复制代码
安装nuget包:
  1. install-package AScript
  2. install-package DynamicExpresso.Core
复制代码
1、常量表达式
  1. 1 // 待测试表达式
  2. 2 private static readonly string s = "100 * (5 + 5) * (6-2)";
  3. 3 // 用于测试结果比较,确保测试执行结果是正确的
  4. 4 private static readonly int r = 100 * (5 + 5) * (6 - 2);
复制代码
分3个测试场景:
1)表明执行
DynamicExpresso不支持表明执行,对AScript的表明执行模式举行测试,以举行综合评价,测试代码如下:
  1. 1 [Benchmark]
  2. 2 public void AScript1()
  3. 3 {
  4. 4     var script = new Script();
  5. 5     var result = script.Eval<int>(s);
  6. 6     if (result != r) throw new Exception("result error");
  7. 7 }
复制代码
2)编译执行
  1. 1 [Benchmark]
  2. 2 public void AScript2_Compile()
  3. 3 {
  4. 4     var script = new Script();
  5. 5     var result = script.Eval<int>(s, ECompileMode.All);
  6. 6     if (result != r) throw new Exception("result error");
  7. 7 }
  8. 8
  9. 9 [Benchmark]
  10. 10 public void Expresso2()
  11. 11 {
  12. 12     var interpreter = new DynamicExpresso.Interpreter();
  13. 13     var result = interpreter.Eval<int>(s);
  14. 14     if (result != r) throw new Exception("result error");
  15. 15 }
复制代码
3)编译缓存
此为通用缓存场景,根据字符串表达式缓存编译生成的委托,提高整体性能。AScript已内置缓存功能,DynamicExpresso需手动添加缓存逻辑。
  1. 1 private static Script _Script3;
  2. 2
  3. 3 [Benchmark]
  4. 4 public void AScript3_Cache()
  5. 5 {
  6. 6     if (_Script3 == null)
  7. 7     {
  8. 8         _Script3 = new Script();
  9. 9     }
  10. 10     var result = _Script3.Eval<int>(s, -1);
  11. 11     if (result != r) throw new Exception("result error");
  12. 12 }
  13. 13
  14. 14 private static readonly ConcurrentDictionary<string, Delegate> _DynamicExpresso3Dict = new ConcurrentDictionary<string, Delegate>();
  15. 15
  16. 16 [Benchmark]
  17. 17 public void Expresso3()
  18. 18 {
  19. 19     string key = s;
  20. 20     if (!_DynamicExpresso3Dict.TryGetValue(key, out var func))
  21. 21     {
  22. 22         var interpreter = new DynamicExpresso.Interpreter();
  23. 23         func = interpreter.ParseAsDelegate<Func<int>>(s);
  24. 24         _DynamicExpresso3Dict[key] = func;
  25. 25     }
  26. 26     var result = ((Func<int>)func)();
  27. 27     if (result != r) throw new Exception("result error");
  28. 28 }
复制代码
测试效果如下:

小结:

  • 表明执行模式对比编译执行模式有肯定优势,因为编译生成委托本钱比力大。
  • 编译执行模式,AScript比DynamicExpresso性能高。
  • 编译缓存模式,DynamicExpresso性能略高于AScript。
2、变量表达式
  1. 1 // 待测试表达式,包含a、b、c三个变量
  2. 2 private static readonly string s = "a * (b + 5) * (c-2)";
  3. 3 // 用于测试结果比较,确保测试执行结果是正确的
  4. 4 private static readonly int r = 100 * (5 + 5) * (6 - 2);
复制代码
分3个测试场景:
1)表明执行
  1. 1 [Benchmark]
  2. 2 public void AScript1()
  3. 3 {
  4. 4     var script = new Script();
  5. 5     script.Context.SetVar("a", 100);
  6. 6     script.Context.SetVar("b", 5);
  7. 7     script.Context.SetVar("c", 6);
  8. 8     var result = script.Eval<int>(s);
  9. 9     if (result != r) throw new Exception("result error");
  10. 10 }
复制代码
2)编译执行
  1. 1 [Benchmark]
  2. 2 public void AScript2_Compile()
  3. 3 {
  4. 4     var script = new Script();
  5. 5     script.Context.SetVar("a", 100);
  6. 6     script.Context.SetVar("b", 5);
  7. 7     script.Context.SetVar("c", 6);
  8. 8     var result = script.Eval<int>(s, ECompileMode.All);
  9. 9     if (result != r) throw new Exception("result error");
  10. 10 }
  11. 11
  12. 12 [Benchmark]
  13. 13 public void Expresso2()
  14. 14 {
  15. 15     var interpreter = new DynamicExpresso.Interpreter();
  16. 16     interpreter.SetVariable("a", 100);
  17. 17     interpreter.SetVariable("b", 5);
  18. 18     interpreter.SetVariable("c", 6);
  19. 19     var result = interpreter.Eval<int>(s);
  20. 20     if (result != r) throw new Exception("result error");
  21. 21 }
复制代码
3)编译缓存
DynamicExpresso编译生成委托后,如果再修改上下文中的变量值,委托执行效果不会变,不会动态从上下文获取变量,以是对DynamicExpresso的编译缓存测试没有意义。
  1. 1 [Benchmark]
  2. 2 public void AScript3_Cache()
  3. 3 {
  4. 4     var script = new Script();
  5. 5     script.Context.SetVar("a", 100);
  6. 6     script.Context.SetVar("b", 5);
  7. 7     script.Context.SetVar("c", 6);
  8. 8     var result = script.Eval<int>(s, -1);
  9. 9     if (result != r) throw new Exception("result error");
  10. 10 }
复制代码
测试效果如下:

 小结:AScript性能优势比力明显。
3、LINQ表达式
  1. 1 private static readonly List<int> _list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  2. 2 // 待测试表达式
  3. 3 private static readonly string s = "list.Where(a => a % 2 == 0).ToList().Count";
  4. 4 // 用于测试结果比较,确保测试执行结果是正确的
  5. 5 private static readonly int r = 5;
复制代码
1)表明执行
  1. 1 [Benchmark]
  2. 2 public void AScript1()
  3. 3 {
  4. 4     var script = new Script();
  5. 5     script.Context.SetVar("list", _list);
  6. 6     var result = script.Eval<int>(s);
  7. 7     if (result != r) throw new Exception("result error");
  8. 8 }
复制代码
2)编译执行
DynamicExpresso执行LINQ表达式需要开启InterpreterOptions.LambdaExpressions选项。
  1. 1 [Benchmark]
  2. 2 public void AScript2_Compile()
  3. 3 {
  4. 4     var script = new Script();
  5. 5     script.Context.SetVar("list", _list);
  6. 6     var result = script.Eval<int>(s, ECompileMode.All);
  7. 7     if (result != r) throw new Exception("result error");
  8. 8 }
  9. 9
  10. 10 [Benchmark]
  11. 11 public void Expresso2()
  12. 12 {
  13. 13     var options = InterpreterOptions.Default | InterpreterOptions.LambdaExpressions;
  14. 14     var interpreter = new DynamicExpresso.Interpreter(options);
  15. 15     interpreter.SetVariable("list", _list);
  16. 16     var result = interpreter.Eval<int>(s);
  17. 17     if (result != r) throw new Exception("result error");
  18. 18 }
复制代码
3)编译缓存
  1. 1 [Benchmark]
  2. 2 public void AScript3_Cache()
  3. 3 {
  4. 4     var script = new Script();
  5. 5     script.Context.SetVar("list", _list);
  6. 6     var result = script.Eval<int>(s, -1);
  7. 7     if (result != r) throw new Exception("result error");
  8. 8 }
复制代码
测试效果如下:

小结:AScript性能优于DynamicExpresso
4、生成委托
  1. 1 [Benchmark]
  2. 2 public void AScript1()
  3. 3 {
  4. 4     var script = new Script();
  5. 5     var func = script.Compile<int, int, int>("a + b", "a", "b");
  6. 6     var result = func(4, 6);
  7. 7     if (result != 10) throw new Exception("result error");
  8. 8 }
  9. 9
  10. 10 [Benchmark]
  11. 11 public void Expresso1()
  12. 12 {
  13. 13     var interpreter = new DynamicExpresso.Interpreter();
  14. 14     var func = interpreter.ParseAsDelegate<Func<int, int, int>>("a + b", "a", "b");
  15. 15     var result = func(4, 6);
  16. 16     if (result != 10) throw new Exception("result error");
  17. 17 }
复制代码
测试效果如下:

小结:AScript性能高。
5、生成Lambda

仅测试生成lambda性能,不做计算。
  1. 1 [Benchmark]
  2. 2 public void AScript1()
  3. 3 {
  4. 4     var script = new Script();
  5. 5     Expression<Func<int, int, int>> lambda = script.Lambda<int, int, int>("a + b", "a", "b");
  6. 6     if (lambda == null) throw new Exception("result error");
  7. 7 }
  8. 8
  9. 9 [Benchmark]
  10. 10 public void Expresso1()
  11. 11 {
  12. 12     var interpreter = new DynamicExpresso.Interpreter();
  13. 13     Expression<Func<int, int, int>> lambda = interpreter.ParseAsExpression<Func<int, int, int>>("a + b", "a", "b");
  14. 14     if (lambda == null) throw new Exception("result error");
  15. 15 }
复制代码
测试效果如下:

小结:AScript性能高。
三 总结

1)AScript支持多语句,DynamicExpresso不支持,通过多次调用Eval方式来实现多语句;
2)AScript比DynamicExpresso性能高,内存占用低;
3)AScript默认为表明执行模式,不缓存也能有较高的性能;
4)AScript内置编译缓存功能,支持缓存版本号和定时缓存,不同应用场景使用合适的缓存策略,来提高项目整体性能。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表