当前位置: 代码迷 >> 综合 >> 转载 Java表达式引擎fel/groovy/expression4j/java脚本引擎的性能对此
  详细解决方案

转载 Java表达式引擎fel/groovy/expression4j/java脚本引擎的性能对此

热度:3   发布时间:2023-12-12 16:31:45.0

转载:http://www.findsrc.com/java/detail/8664

产品中需要用到数学表达式,表达式不复杂,但是对性能要求比较高。选用了一些常用的表达式引擎计算方案,包含:java脚本引擎(javax/script)、groovy脚本引擎、Expression4j、Fel表达式引擎。

其中java脚本引擎使用了解释执行和编译执行两种方式、groovy脚本只采用了编译执行(解释执行太慢)、Fel采用了静态参数和动态参数两种方式。以下为测试代码:

public class ExpressionTest extends BaseTest {

private int count = 100000;//javax的编译执行,效率比解释执行略高?为什么才略高??
@Test
public void testCompiledJsScript() throws Throwable {javax.script.ScriptEngine se = new ScriptEngineManager().getEngineByName("js");Compilable ce = (Compilable) se;CompiledScript cs = ce.compile("a*b*c");Bindings bindings = se.createBindings();bindings.put("a", 3600);bindings.put("b", 14);bindings.put("c", 4);long start = System.currentTimeMillis();for (int i = 0; i < count; i++) {cs.eval(bindings);}System.out.println(System.currentTimeMillis() - start);
}//javax script解释执行
@Test
public void testJsScript() throws Throwable {javax.script.ScriptEngine se = new ScriptEngineManager().getEngineByName("js");Bindings bindings = se.createBindings();bindings.put("a", 3600);bindings.put("b", 14);bindings.put("c", 4);long start = System.currentTimeMillis();for (int i = 0; i < count; i++) {se.eval("a*b*c", bindings);}System.out.println(System.currentTimeMillis() - start);
}//groovy的编译执行
@Test
public void testGroovy() {//这里的ScriptEngine和GroovyScriptEngine是自己编写的类,不是原生的ScriptEngine se = this.getBean(GroovyScriptEngine.class);Map<String, Object> paramMap = new HashMap<String, Object>();paramMap.put("param", 5);//ScriptEngine首次执行会缓存编译后的脚本,这里故意先执行一次便于缓存se.eval("3600*34*param", paramMap);long start = System.currentTimeMillis();for (int i = 0; i < count; i++) {se.eval("3600*34*param", paramMap);}System.out.println(System.currentTimeMillis() - start);
}//Expression4J的表达式引擎,这里是通过函数的方式,有点特别
@Test
public void testExpression4j() throws Throwable {Expression expression = ExpressionFactory.createExpression("f(a,b,c)=a*b*c");System.out.println("Expression name: " + expression.getName());System.out.println("Expression parameters: " + expression.getParameters());MathematicalElement element_a = NumberFactory.createReal(3600);MathematicalElement element_b = NumberFactory.createReal(34);MathematicalElement element_c = NumberFactory.createReal(5);Parameters parameters = ExpressionFactory.createParameters();parameters.addParameter("a", element_a);parameters.addParameter("b", element_b);parameters.addParameter("c", element_c);long start = System.currentTimeMillis();for (int i = 0; i < count; i++) {expression.evaluate(parameters);}System.out.println(System.currentTimeMillis() - start);
}//fel的表达式引擎(静态参数,同上面)
@Test
public void felTest() {FelEngine e = FelEngine.instance;final FelContext ctx = e.getContext();ctx.set("a", 3600);ctx.set("b", 14);ctx.set("c", 5);com.greenpineyu.fel.Expression exp = e.compile("a*b*c", ctx);long start = System.currentTimeMillis();Object eval = null;for (int i = 0; i < count; i++) {eval = exp.eval(ctx);}System.out.println(System.currentTimeMillis() - start);System.out.println(eval);
}//fel表达式引擎(动态参数,这里动态参数的产生和变量改变都会消耗时间,因此这个测试时间不准确,只是验证对于动态参数的支持)
@Test
public void felDynaTest() {FelEngine e = FelEngine.instance;final FelContext ctx = e.getContext();ctx.set("a", 3600);ctx.set("b", 14);ctx.set("c", 5);com.greenpineyu.fel.Expression exp = e.compile("a*b*c", ctx);long start = System.currentTimeMillis();Object eval = null;Random r = new Random();for (int i = 0; i < count; i++) {ctx.set("a", r.nextInt(10000));ctx.set("b", r.nextInt(100));ctx.set("c", r.nextInt(100));eval = exp.eval(ctx);}System.out.println(System.currentTimeMillis() - start);System.out.println(eval);
}public static void main(String[] args) throws Throwable {ExpressionTest et = new ExpressionTest();//执行100W次的测试et.count = 1000000;et.testCompiledJsScript();et.testJsScript();et.testExpression4j();et.testGroovy();et.felTest();
}

}

测试结果如下:

表达式引擎 执行时间(毫秒) 备注
java脚本引擎编译后执行

7662

java脚本引擎解释执行 10609
expression4j 578
groovy编译执行 224
fel静态参数 19
fel动态参数 107 该项测试比较不公平,随机数的产生以及参数的变更也会占用一定时间,测试目的只是为了验证是不是存在静态优化,从而导致静态性能远高于动态性能的情况。

结论:

从以上性能对比来看(抛开表达式的功能),fel明显占据很大优势,groovy和expression4j也是可以接受的。java脚本引擎的执行偏慢。因此,对于表达式不是很复杂性能要求高的情况下,推荐使用fel或者groovy编译执行的方式。

  相关解决方案