使用缓存增加批量Groovy eval()

时间:2011-05-19 13:56:23

标签: groovy

我正在编写一个批处理excel文件的程序。将每行的数据放入映射中,文件名和工作表名称确定处理获取的数据的脚本。这些脚本没有捆绑到我的程序中,它们甚至不是实现特定接口的类。

这是处理循环逻辑:

excelfile.eachLineOnSheet { line, sheet ->
  def data = extractData();
  def lineprocessorscript = determineLineProcessor(excelfile, sheet);

  Eval.xy data, outputfile, lineprocessorscript

}

当然这很容易,但在大文件上我想提高性能。首先我缓存了行处理器的代码,以便.groovy文件只读一次。

是否有可能通过以某种方式缓存编译的脚本来加快Eval.xy的速度? 我想保持我的脚本简单,以便不实现任何接口或东西。

5 个答案:

答案 0 :(得分:3)

我对它的看法

deg gcl = ... // probably new GroovyClassLoader(this.class.classLoader)
def cache = [:].withDefault{gcl.parseClass(new File(it))}
...
lineprocessors.each {
  cache[it].newInstance([someVariable:1, otherVariable:2] as Binding).run()
}

关于你自己答案的几条评论 你不需要自己创建gsc,只需用gcl加载文件。
如果你正在处理脚本,你真的不需要InvokerHelper,你可以自己实例化它们 利用groovy syntax = D

答案 1 :(得分:1)

Eval.xy调用GroovyShell.evaluate方法。各种形式的GroovyShell.evaluate都归结为这种形式:

public Object evaluate(GroovyCodeSource codeSource) 
        throws CompilationFailedException {
    Script script = parse(codeSource);
    script.setBinding(context);
    return script.run();
}

我还没有尝试过,但您可以通过为XLS表中的每一行使用不同的绑定调用它来重用Script对象。

答案 2 :(得分:1)

@Binil托马斯回答帮助我开始。我查看了Groovy源代码,发现GroovyClassLoader有一个内置缓存,但是从Eval方向调用时,缓存已关闭:

private Class parseClass(final GroovyCodeSource codeSource) throws CompilationFailedException {
  // Don't cache scripts
  return loader.parseClass(codeSource, false);
}

为什么不缓存脚本..?这正是我需要的...... :-)所以我写了Eval根据来源做的东西,这就出来了:

lineprocessors.each {

  if(cachedLineProcessorCodes[it] == null) {
    def gsc = new GroovyCodeSource(new File(it).getText(), it, 'DEFAULT_CODE_BASE')
    Class cc = gcl.parseClass(gsc, true)
    cachedLineProcessorCodes[it] = cc
  }

  def binding = new Binding()
  binding.setVariable("x", linedata)
  binding.setVariable("y", lineProcFiles[it])

  def Script sc = InvokerHelper.createScript(cachedLineProcessorCodes[it], binding)
  sc.run()

  //Eval.xy linedata, lineProcFiles[it], new File(it).getText()

}

在我的情况下,当groovy脚本处理7900行时,运行时间从~73s减少到~5s。

答案 3 :(得分:1)

您还可以通过测试http://mvel.codehaus.org/Performance+of+MVEL+2.0更快地将MVEL用于此类任务,而且不会更困难。

答案 4 :(得分:0)

你应该预先编写你的脚本,这通常是最激烈的部分:

String code = '$obj.toString()'
GroovyShell shell = new GroovyShell()
Script script = shell.parse(code, 'preparsed')
items.each {item ->
  sh.setVariable('$obj', item)
  Object result = s.run()
}