Search code examples
javaperformancegroovyperformance-testingbeanshell

Great difference in Time Execution Groovy vs Beanshell


I'm interpreting a same script in both Groovy and Beanshell.

Groovy takes a very long time(26 mins 25 secs), while Beanshell takes only 20 secs.

I'm very astonished by the difference and I don't understand why, Is Beanshell is better? Am I using Groovy is wrong?

Groovy code:

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 code:

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);

      }

Main:

 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();
            }

        }

Solution

  • You better use Groovy 2 compiled statically feature

    Since version 2, Groovy can also be compiled statically, offering type inference, and performance near that of Java

    In your case for each iteration call same script outside of the loop:

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

    Also script can be marked as CompileStatic, for example:

    import groovy.transform.CompileStatic
    
    @CompileStatic
    int squarePlusOne(int num) {
       num * num + 1
    }
    
    assert squarePlusOne(3) == 10