锁定老帖子 主题:FEL(表达式语言)——7月30号更新
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-03-11
最后修改:2011-03-11
superobin 写道 其实,像这种需要用表达式的地方往往不是时常变动的(否则就用动态与言了)。
一般就是一个公式类的东西需要反复执行,这个公式可以带若干个参数或者一些调用。如果这种情况需要反复执行(如对数据库表中数据逐条执行)这种情况,那么编译出来一定效率更高。 编译时就用执行语句的顺序去写字节码,实际执行的时候就像原生代码一样高效了。 我这里使用的是objectweb的asm包,貌似cglib也行。不过好像由于它经过封装了貌似没那么灵活 虽然没有看到你写的四则运算编译器的源码,但是挺佩服你的作品。 另外你说的一个公式与数据表中的记录逐条执行这种方式确实挺常见,不知道你出于什么原因要将其编译成字节码。不编译也很高效(当然比不上编译的那么高效)。 |
|
返回顶楼 | |
发表时间:2011-03-12
编成字节码的确是个思路,之前完全没想到过,缺乏这些知识限制了思路
以前的需求就是通过定义的公式到数据库取列然后列和列做运算,只不过要先在时间维度和对象维度累加计算因子,然后做运算,实际上累加比公式这块麻烦 公式解析另外用的地方是作为数据集过滤器替代oracle的sql排序实现topn查询,公式部分是用来计算where后面的真假值,如 where 成功率>0.99 and (a次数+b次数)>100 |
|
返回顶楼 | |
发表时间:2011-03-12
lotusyu 写道 superobin 写道 其实,像这种需要用表达式的地方往往不是时常变动的(否则就用动态与言了)。
一般就是一个公式类的东西需要反复执行,这个公式可以带若干个参数或者一些调用。如果这种情况需要反复执行(如对数据库表中数据逐条执行)这种情况,那么编译出来一定效率更高。 编译时就用执行语句的顺序去写字节码,实际执行的时候就像原生代码一样高效了。 我这里使用的是objectweb的asm包,貌似cglib也行。不过好像由于它经过封装了貌似没那么灵活 虽然没有看到你写的四则运算编译器的源码,但是挺佩服你的作品。 另外你说的一个公式与数据表中的记录逐条执行这种方式确实挺常见,不知道你出于什么原因要将其编译成字节码。不编译也很高效(当然比不上编译的那么高效)。 其实这个思路源于对我们部门的一次考试题(都工作了还考试,可恶- -),涉及到公式计算(当然,主要是想考子类、重写等知识点)。后来整理代码的时候就想,这个公式是否可以变成可以用配置文件配置的,而不是用子类去实现。比如:girth= 2*PI*radius。 后来写出来一个动态执行的,但是感觉性能有明显下降,因为数据量是比较大的,100W左右,所以性能就是个的问题了。 后来尝试在加载的时候将表达式编译成字节码,这样就和原生代码一样了,性能就达到了预期标准。 |
|
返回顶楼 | |
发表时间:2011-03-13
语法文件Er.g是不是可以提供出来?
|
|
返回顶楼 | |
发表时间:2011-03-14
jjxlcsw 写道 语法文件Er.g是不是可以提供出来?
谢谢你的关注。语法文件目前还在整理中,整理好了之后,我再传到google code中去。 |
|
返回顶楼 | |
发表时间:2011-03-15
ok, 等你的大作。。。。。。。。。
|
|
返回顶楼 | |
发表时间:2011-03-16
以前demo的代码翻出来测试了一下
static public void test3(){ long start,end; String formula="kpi1/(kpi2*(kpi4+kpi5*kpi3)-kpi6)/kpi7"; Expression root = BasicParser.parseFormula(formula); root.putValueToExpre("kpi1", 40d); root.putValueToExpre("kpi2", 123d); root.putValueToExpre("kpi3", 31d); root.putValueToExpre("kpi4", 12d); root.putValueToExpre("kpi5", 46d); root.putValueToExpre("kpi6", 4d); root.putValueToExpre("kpi7", 23d); Calendar calendar1 = Calendar.getInstance(); int num=100000000; start=System.currentTimeMillis(); for(int i=0;i<num;i++){ root.getExpressionValue(); } end=System.currentTimeMillis(); Calendar calendar2 = Calendar.getInstance(); long costTime=end-start; float totalTime= calendar2.getTimeInMillis()-calendar1.getTimeInMillis(); float avgTime=totalTime/num; System.out.println("表达式:"+formula+"\n计算次数:"+num+",花费时间:"+totalTime+"毫秒 "+costTime+"\n平均计算花费时间:"+avgTime+"毫秒"); System.out.println(root.getExpressionValue()); formula="40.52334+60*(21.8144+17*32.663)"; root = BasicParser.parseFormula(formula); start=System.currentTimeMillis(); for(int i=0;i<num;i++){ root.getExpressionValue(); } end=System.currentTimeMillis(); costTime=end-start; System.out.println("表达式:"+formula+"\n计算次数:"+num+",花费时间:"+costTime); System.out.println(root.getExpressionValue()); } 测试结果 表达式:kpi1/(kpi2*(kpi4+kpi5*kpi3)-kpi6)/kpi7 计算次数:100000000,花费时间:16992.0毫秒 16992 平均计算花费时间:1.6992E-4毫秒 9.832817520114257E-6 表达式:40.52334+60*(21.8144+17*32.663) 计算次数:100000000,花费时间:5477 34665.647339999996 cpu为intel8400,无其他负载 数字表达式如果单测大概2100左右,但放变量表达式后面一起跑就慢了一倍多,找不到原因 数组挂靠应该比数字表达式慢,但应该是一个数量级 以前做查询过滤器一次数据不会过20w,计算kpi每秒不会过w,对server速度足够了 写这个代码的时候cpu应该是amd3000+,测起来应该比较寒碜了,一直想换c++然后去函数化看看最快能到多少 |
|
返回顶楼 | |
发表时间:2011-03-16
el 语言是个比较重要的东西, 有些系统需要一些动态执行脚本, 提取数据的能力。
楼上的, c++实现也未必快到哪儿去。 这点时间, 大部分系统下, 意义不是太。 |
|
返回顶楼 | |
发表时间:2011-03-16
看看OSworkflow的脚本功能,那东西强大
|
|
返回顶楼 | |
发表时间:2011-03-16
最后修改:2011-03-16
jjxlcsw 写道 ok, 等你的大作。。。。。。。。。
大作不敢当,交流一下还是可以的。留下你的邮箱,我发给你。 |
|
返回顶楼 | |