简体   繁体   中英

How to increase performance of Groovy?

I'm using Groovy to execute some piece of Java code. For my purpose Groovy it's easy to use since the code I have to execute has an arbitrary number of params that I cannot predict, since it depends on the user input. The input I'm talking about is OWL axioms, that are nested. This is my code:

//The reflection
static void reflectionToOwl() {
    Binding binding = new Binding(); //155 ms
    GroovyShell shell = new GroovyShell(binding);
    while (!OWLMapping.axiomStack.isEmpty()) {
        String s = OWLMapping.axiomStack.pop();
        shell.evaluate(s); //350 ms
    }
}

The only bottleneck in my program is exactly here. More is the data I have to process more is the ms I have to wait for. Do you have any suggestions?

If you need to increase Groovy performance, you can use @CompileStatic annotation.

This will let the Groovy compiler use compile time checks in the style of Java then perform static compilation, thus bypassing the Groovy meta object protocol.

Just annotate specific method with it. But be sure that you don't use any dynamic features in that scope.

As an example:

import groovy.transform.CompileStatic

@CompileStatic
class Static {

}

class Dynamic {

}

println Static.declaredMethods.length
Static.declaredMethods.collect { it.name }.each { println it }

println('-' * 100)

println Dynamic.declaredMethods.length
Dynamic.declaredMethods.collect{ it.name }.each { println it }

Won't generate some extra methods:

6
invokeMethod
getMetaClass
setMetaClass
$getStaticMetaClass
setProperty
getProperty


8
invokeMethod
getMetaClass
setMetaClass
$getStaticMetaClass
$getCallSiteArray
$createCallSiteArray
setProperty
getProperty

Like the first answer indicated, @CompileStatic would have been the first option on my list of tricks as well.

Depending on your use case, pre-parsing the script expressions and calling 'run' on them execution time might be an option here. The following code demonstrates the idea:

def exprs = [
  "(1..10).sum()", 
  "[1,2,3].max()"
]

def shell = new GroovyShell()

def scripts = time("parse exprs") { 
  exprs.collect { expr ->
    shell.parse(expr) // here we pre-parse the strings to groovy Script instances
  }
}

def standardBindings = [someKey: 'someValue', someOtherKey: 'someOtherValue']
scripts.eachWithIndex { script, i ->
  time("run $i") {
    script.binding = new Binding(standardBindings)
    def result = script.run() // execute the pre-parsed Script instance   
  }
}

// just a small method for timing operations
def time(str, closure) {
  def start = System.currentTimeMillis()

  def result = closure()

  def delta = System.currentTimeMillis() - start
  println "$str took $delta ms -> result $result"

  result
}

which prints:

parse exprs took 23 ms -> result [Script1@1165b38, Script2@4c12331b]
run 0 took 7 ms -> result 55
run 1 took 1 ms -> result 3

on my admittedly aging laptop.

The above code operates in two steps:

  1. parse the String expressions into Script instances using shell.parse. This can be done in a background thread, on startup or otherwise while the user is not waiting for results.
  2. "execution time" we call script.run() on the pre-parsed script instances. This should be faster than calling shell.evaluate.

The takeaway here is that if your use case allows for pre-parsing and has a need for runtime execution speed, it's possible to get quite decent performance with this pattern.

An example application I have used this in is a generic feed file import process where the expressions were customer editable data mapping expressions and the data was millions of lines of product data. You parse the expressions once and call script.run millions of times. In this kind of scenario pre-parsing saves a lot of cycles.

Insted of Groovy you can also use BeanShell. It is supereasy to use and it is very light: Website

Probably not all Java function are supported, but just give a try.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM