【问题标题】:Great difference in Time Execution Groovy vs Beanshell时间执行 Groovy 与 Beanshell 的巨大差异
【发布时间】:2018-04-18 16:13:03
【问题描述】:

我在 Groovy 和 Beanshell 中解释相同的脚本。

Groovy 需要很长时间(26 分 25 秒),而 Beanshell 只需要 20 秒。

我对这种差异感到非常惊讶,我不明白为什么,Beanshell 更好吗?我使用 Groovy 是不是错了?

Groovy 代码

public  void calcule_irg(double salaire) throws Throwable{
        Binding binding = new Binding();
        binding.setVariable("MNT_943", 0);
       String script="double formule_irg(Double salaireSoumis) {\n" +
"    int salaire = salaireSoumis.intValue();\n" +
"    salaire = salaire / 10 * 10;\n" +
"                \n" +
"    Double impots = 0.0;\n" +
"                \n" +
"    if (salaire >= 15000 && salaire <= 22500) {\n" +
"        impots = ((salaire - 10000) * 0.2) - 1000.0;\n" +
"    } else if (salaire > 22500 && salaire <= 30000) {\n" +
"        impots = ((salaire - 10000) * 0.2);\n" +
"        impots = impots - (impots * 0.4);\n" +
"    } else if (salaire >= 30001 && salaire <= 120000) {\n" +
"        impots = 2500 + ((salaire - 30000) * 0.3);\n" +
"    } else if (salaire >= 120001) {\n" +
"        impots = 29500 + ((salaire - 120000) * 0.35);\n" +
"    } else {\n" +
"        impots = 0.0;\n" +
"    }\n" +
"                \n" +

"    return impots.intValue();\n" +
"} \n" +
"\n" +
"MNT_943 = formule_irg("+salaire+") ;\n";
        GroovyShell shell = new GroovyShell(binding);
        shell.evaluate(script);

        Double   value =(Double) shell.getVariable("MNT_943");

    }

Beanshell 代码

public  void calcule_irg(double salaire) throws EvalError {
           Interpreter i = new Interpreter();  // Construct an interpreter

        // Eval a statement and get the result
         String script="double formule_irg(Double salaireSoumis) {\n" +
"    int salaire = salaireSoumis.intValue();\n" +
"    salaire = salaire / 10 * 10;\n" +
"                \n" +
"    Double impots = 0.0;\n" +
"                \n" +
"    if (salaire >= 15000 && salaire <= 22500) {\n" +
"        impots = ((salaire - 10000) * 0.2) - 1000.0;\n" +
"    } else if (salaire > 22500 && salaire <= 30000) {\n" +
"        impots = ((salaire - 10000) * 0.2);\n" +
"        impots = impots - (impots * 0.4);\n" +
"    } else if (salaire >= 30001 && salaire <= 120000) {\n" +
"        impots = 2500 + ((salaire - 30000) * 0.3);\n" +
"    } else if (salaire >= 120001) {\n" +
"        impots = 29500 + ((salaire - 120000) * 0.35);\n" +
"    } else {\n" +
"        impots = 0.0;\n" +
"    }\n" +
"                \n" +

"    return impots.intValue();\n" +
"} \n" +
"\n" +
"MNT_943 = formule_irg("+salaire+") ;\n";
        i.eval(script);

      }

主要

 public static void main(String[] args) throws Throwable{

            Groovy g=new Groovy();// The function mentioned below is defined in a class named Groovy
            Beanshell s=new Beanshell();// The function mentioned below is defined in a class named Beanshell


            String fileName = "c://salaires100K.txt";

            //read file into stream, try-with-resources
            try (Stream<String> stream = Files.lines(Paths.get(fileName))) {//This file contains 100'000 Salary, means 100'000 lines

                stream.forEach( n->{
                    try {
                      g.calcule_irg(Double.parseDouble(n));//I use either this 
                      //s.calcule_irg(Double.parseDouble(n));//Or this
                    } catch (Throwable ex) {
                        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                    }
                });

            } catch (IOException e) {
                e.printStackTrace();
            }

        }

【问题讨论】:

  • 当你说它需要很长时间时,你是在循环执行这个吗?
  • 是的,100'000 次迭代 @DodgyCodeException
  • 您是否在每次迭代中重复编译脚本?不是脚本本身需要时间来运行;这是它的编译。我认为这是因为 Groovy 将其编译成 Java 字节码然后运行它,而 Beanshell 只是在解释它时使用实际的脚本。
  • @DodgyCodeException 用 Main 方法更新了我的问题

标签: java performance groovy performance-testing beanshell


【解决方案1】:

你最好使用Groovy 2 静态编译功能

从第 2 版开始,Groovy 也可以静态编译,提供类型推断和接近 Java 的性能

在您的情况下,每次迭代都在循环外调用相同的脚本:

compiledScript = ((Compilable) scriptEngine).compile(script);
compiledScript.eval(binding);

也可以将脚本标记为CompileStatic,例如:

import groovy.transform.CompileStatic

@CompileStatic
int squarePlusOne(int num) {
   num * num + 1
}

assert squarePlusOne(3) == 10 

【讨论】:

  • 主要是在循环外只调用一次compiledScript = ((Compilable) scriptEngine).compile(script);
  • 已添加outside of the loop 评论
  • 不是同一个脚本,只要它包含salaire变量,它在每次迭代中都连接到它,所以它是动态脚本,见这一行:` + "MNT_943 = formule_irg("+salaire+ ") ;\n";`
  • 不要将salaire值连接到脚本本身,而是使用变量绑定来代替。
  • 感谢大家,这行得通,而且执行时间也好很多
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多