• .NET Flee 字符串表达式动态解析,怎么性能优化!!


    Flee

    使用介绍

    Flee (支持 Net6.0, Net5.0, Netstandard2.1, Netstandard2.0)
    动态解析的框架是有几个的,个人先使用了DynamicExpresso,但是需求中是需要支持IF/ELSE的,DynamicExpresso中支持三目运算,可以代替IF/ELSE,需要对字符串表达式进行IF/ELSE到三目运算的转换才能使用,之后发现了Flee直接支持。
    DynamicExpresso和Flee相比较,个人感觉Flee的性能更好,支持的功能也比较多。Flee支持自定函数,可以进行类的导入,其他变量等各个框架都有的功能就不详细说了。大家可以体验自行对比下。

    DynamicExpresso
    Flee

    在这里插入图片描述
    在这里插入图片描述
    Flee的用法都可以参照官网的demo进行使用,还是比较详细的。

    性能优化

    在我项目中的场景是需要对表达式相同,但其中变量不同的表达式进行多次运算。
    我这里大概需要循环2w次左右,有2w条数据需要计算

    第一种 直接循环

                    for (int i = 0; i < scurveFormulasSource.Count; i++)
                    {
                     	ExpressionContext context = new ExpressionContext();
                    	context.Imports.AddType(typeof(Math));
                    	 //赋值变量
                        foreach (var item in scurveFormulasSource[i])
                        {
                            context.Variables[item.Key.Replace("*", "")] = item.Value;
                        }
                    	IGenericExpression<double> exp = context.CompileGeneric<double>(input.Text);
     
                        double result = Math.Round(exp.Evaluate(), 2);
                    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这样计算大概需要4s

    第二种 共用表达式

    因为我每次的表达式是相同的,所以我想着可以用一个表达式,也就是IGenericExpression exp = context.CompileGeneric(input.Text);这段代码提取出来,不参与循环,循环中只进行赋值。如下代码

                    ExpressionContext context = new ExpressionContext();
                    context.Imports.AddType(typeof(Math));
                    IGenericExpression<double> exp = context.CompileGeneric<double>(input.Text);
                    for (int i = 0; i < scurveFormulasSource.Count; i++)
                    {
                    	 //赋值变量
                        foreach (var item in scurveFormulasSource[i])
                        {
                            context.Variables[item.Key.Replace("*", "")] = item.Value;
                        }
    
                        double result = Math.Round(exp.Evaluate(), 2);
                    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这样的代码运行后会报错,提示找不到我定义的变量,在GenericExpression exp = context.CompileGeneric(input.Text); 构建表达式的时候就会进行变量检查,如果没有表达式里的变量就会抛出异常。

    我们可以做如下处理,在构建表达式之前先对变量进行赋值定义,之后再修改值 这样就不会抛出异常了。如下

                    ExpressionContext context = new ExpressionContext();
                    context.Imports.AddType(typeof(Math));
                     //赋值变量
                    foreach (var item in scurveFormulasSource[i])
                    {
                    	context.Variables[item.Key.Replace("*", "")] = item.Value;
                    }
                    IGenericExpression<double> exp = context.CompileGeneric<double>(input.Text);
                    for (int i = 0; i < scurveFormulasSource.Count; i++)
                    {
                    	 //赋值变量
                        foreach (var item in scurveFormulasSource[i])
                        {
                            context.Variables[item.Key.Replace("*", "")] = item.Value;
                        }
    
                        double result = Math.Round(exp.Evaluate(), 2);
                    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在获取表达式之前先定义出变量,之后修改值,这样修改后本次的运行时间为20毫秒左右。

  • 相关阅读:
    vue框架学习-----vue简介&vue.js安装&第一个vue程序&部分vue指令
    Linux内存不够了?看看如何开启虚拟内存增加内存使用量
    TCP协议之《对端MSS值估算》
    myj的尘歌壶
    简单实现接口自动化测试(基于python)
    <学习笔记>从零开始自学Python-之-web应用框架Django(一)从Hello World 到 MTV
    快速求N!
    贪心算法-Huffman算法
    Golang 重返Leetcode战场之旅(Leetcode Go总结博客)
    基于JavaEE的大学生公寓管理系统
  • 原文地址:https://blog.csdn.net/Maybe_ch/article/details/126765960