With Java ScriptEngine (Groovy), how to make it more performant?

matsientst picture matsientst · Aug 31, 2012 · Viewed 8.2k times · Source

I am using ScriptEngine in my app to evaluate some client code in my application. The problem is it's not performant enough and I need to take measures to improve the time of execution. Currently, it can take up to 1463ms (average is around 300ms) to eval an extremely simple script which is basically parameter replacement in URLs.

I'm looking for simple strategies to improve this performance without losing the scripting ability.

My first thought it to pool the ScriptEngine object and reuse it. I see in the spec it's meant to be reused but I haven't found any examples of anyone actually doing it.

Any ideas? Here is my code:

ScriptEngineManager factory = new ScriptEngineManager();
GroovyScriptEngineImpl engine = (GroovyScriptEngineImpl)factory.getEngineByName("groovy");
engine.put("state", state;
engine.put("zipcode", zip);
engine.put("url", locationAwareAd.getLocationData().getGeneratedUrl());
url = (String) engine.eval(urlGeneratorScript);

Any feedback would be appreciated!

Answer

Anton Arhipov picture Anton Arhipov · Aug 31, 2012

Most likely the problem is that the engine actually evaluates the script every time eval() is called. Instead, you could re-use the precompiled script via Compilable interface.

    // move this into initialization part so that you do not call this every time.
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine  = manager.getEngineByName("groovy");
    CompiledScript script = ((Compilable) engine).compile(urlGeneratorScript);

    //the code below will use the precompiled script code
    Bindings bindings = new Bindings();
    bindings.put("state", state;
    bindings.put("zipcode", zip);
    bindings.put("url", locationAwareAd.getLocationData().getGeneratedUrl());
    url = script.eval(bindings);

FWIW, you can also implement the file timestamp check, if the script is changed call compile(..) again.