Java 在运行时重新加载Groovy脚本

Java 在运行时重新加载Groovy脚本,java,groovy,runtime,Java,Groovy,Runtime,我想成为一名能够从Java应用程序执行groovy脚本的程序员。 如果需要,我想在运行时重新加载groovy脚本。根据他们的说法,我可以这样做: long now = System.currentTimeMillis(); for(int i = 0; i < 100000; i++) { try { GroovyScriptEngine groovyScriptEngine = new GroovyScriptEngine("");

我想成为一名能够从Java应用程序执行groovy脚本的程序员。 如果需要,我想在运行时重新加载groovy脚本。根据他们的说法,我可以这样做:

long now = System.currentTimeMillis();
for(int i = 0; i < 100000; i++) {
    try {
        GroovyScriptEngine groovyScriptEngine = new GroovyScriptEngine("");                
        System.out.println(groovyScriptEngine.run("myScript.groovy", new Binding()););
    } catch (Exception e) {
        e.printStackTrace();
    }
}
long end = System.currentTimeMillis();

System.out.println("time " + (end - now));//24 secs
这很好,每次我在myScript.groovy中更改一行时都会重新加载脚本

问题是,这并没有时间效率,它所做的是每次都从文件中解析脚本

还有其他选择吗?例如,检查脚本是否已被解析,以及自上次解析以来脚本是否没有更改的更智能的工具,请不要再次解析它。

>

正如其中一条注释中提到的,如果需要性能,必须将解析(速度慢)与执行(速度快)分开

例如,对于脚本源的反应式重新加载,我们可以使用:

每当对源文件进行更改时,都会打印重新加载的
源…

我对windows不太清楚,但我相信至少在linux上,java在幕后使用了fsnotify系统,这将使文件监控部分发挥作用

应该注意的是,如果我们真的不走运,脚本变量将由两行之间的观察线程重置:

  script.setBinding(binding)
  def result = script.run()
这将破坏代码,因为重新加载的脚本实例没有绑定集。要解决此问题,例如,我们可以使用锁:

import groovy.lang.*
import java.nio.file.*
import java.util.concurrent.locks.ReentrantLock

def source = new File('script.groovy')
def shell  = new GroovyShell()
def script = shell.parse(source.text)

def watchService = FileSystems.default.newWatchService()
source.canonicalFile.parentFile.toPath().register(watchService, StandardWatchEventKinds.ENTRY_MODIFY)

lock = new ReentrantLock()

boolean keepWatching = true 
Thread.start { 
  while (keepWatching) {
    def key = watchService.take()
    if (key.pollEvents()?.any { it.context() == source.toPath() }) {
      withLock { 
        script = shell.parse(source.text)
      }
      println "source reloaded..."
    }
    key.reset()
  }
}

def binding = new Binding()
def start = System.currentTimeMillis()
for (i=0; i<100; i++) {
  withLock { 
    script.setBinding(binding)
    def result = script.run()
    println "script ran: $result"
  }
  Thread.sleep(500)
} 
def delta = System.currentTimeMillis() - start
println "took ${delta}ms"

keepWatching = false

def withLock(Closure c) {
  def result
  lock.lock()
  try { 
    result = c()
  } finally { 
    lock.unlock()
  }
  result
}
导入groovy.lang*
导入java.nio.file*
导入java.util.concurrent.locks.ReentrantLock
def source=新文件('script.groovy')
def shell=newgroovyshell()
def script=shell.parse(source.text)
def watchService=FileSystems.default.newWatchService()
source.canonicalFile.parentFile.toPath().register(watchService、StandardWatchEventTypes.ENTRY\u MODIFY)
lock=new ReentrantLock()
布尔值keepWatching=true
Thread.start{
同时(继续观察){
def key=watchService.take()
if(key.pollEvents()?.any{it.context()==source.toPath()}){
带锁{
script=shell.parse(source.text)
}
println“源重新加载…”
}
key.reset()
}
}
def binding=新绑定()
def start=System.currentTimeMillis()
对于(i=0;i>

正如其中一条注释中提到的,如果需要性能,必须将解析(速度慢)与执行(速度快)分开

例如,对于脚本源的反应式重新加载,我们可以使用:

每当对源文件进行更改时,都会打印重新加载的
源…

我对windows不太清楚,但我相信至少在linux上,java在幕后使用了fsnotify系统,这将使文件监控部分发挥作用

应该注意的是,如果我们真的不走运,脚本变量将由两行之间的观察线程重置:

  script.setBinding(binding)
  def result = script.run()
这将破坏代码,因为重新加载的脚本实例没有绑定集。要解决此问题,我们可以使用锁:

import groovy.lang.*
import java.nio.file.*
import java.util.concurrent.locks.ReentrantLock

def source = new File('script.groovy')
def shell  = new GroovyShell()
def script = shell.parse(source.text)

def watchService = FileSystems.default.newWatchService()
source.canonicalFile.parentFile.toPath().register(watchService, StandardWatchEventKinds.ENTRY_MODIFY)

lock = new ReentrantLock()

boolean keepWatching = true 
Thread.start { 
  while (keepWatching) {
    def key = watchService.take()
    if (key.pollEvents()?.any { it.context() == source.toPath() }) {
      withLock { 
        script = shell.parse(source.text)
      }
      println "source reloaded..."
    }
    key.reset()
  }
}

def binding = new Binding()
def start = System.currentTimeMillis()
for (i=0; i<100; i++) {
  withLock { 
    script.setBinding(binding)
    def result = script.run()
    println "script ran: $result"
  }
  Thread.sleep(500)
} 
def delta = System.currentTimeMillis() - start
println "took ${delta}ms"

keepWatching = false

def withLock(Closure c) {
  def result
  lock.lock()
  try { 
    result = c()
  } finally { 
    lock.unlock()
  }
  result
}
导入groovy.lang*
导入java.nio.file*
导入java.util.concurrent.locks.ReentrantLock
def source=新文件('script.groovy')
def shell=newgroovyshell()
def script=shell.parse(source.text)
def watchService=FileSystems.default.newWatchService()
source.canonicalFile.parentFile.toPath().register(watchService、StandardWatchEventTypes.ENTRY\u MODIFY)
lock=new ReentrantLock()
布尔值keepWatching=true
Thread.start{
同时(继续观察){
def key=watchService.take()
if(key.pollEvents()?.any{it.context()==source.toPath()}){
带锁{
script=shell.parse(source.text)
}
println“源重新加载…”
}
key.reset()
}
}
def binding=新绑定()
def start=System.currentTimeMillis()

对于(i=0;仅当
file.lastModified()
与前面的部分不同时,我才加载脚本。我会尝试一下,但我更喜欢使用solid solution,而不是对file.lastModified()file.lastModified()进行“hack”速度也很慢,但比一次又一次地解析脚本要好。@daggett还知道从外部资源加载脚本的最佳方式吗?(例如从http webservice)
def script=GroovyShell.parse(URI);script.setBinding(…);script.run()
而且还不清楚在100K循环中测量的是什么…最好是拆分解析和运行…只有当
file.lastModified()与前面的部分不同时才重新加载脚本。我会尝试一下,但我更喜欢一个解决方案,而不是对file.lastModified()file.lastModified()进行“黑客攻击”速度也很慢,但比一次又一次地解析脚本要好。@daggett还知道从外部资源加载脚本的最佳方式吗?(例如从http webservice)
def script=GroovyShell.parse(URI);script.setBinding(…);script.run()
不清楚100K循环中测量的是什么…最好将解析和运行分开…我知道这是性能的关键…我想找到在需要时重新解析脚本的最佳方法。我只能选择两种方法中的一种。每X分钟重新解析一次或手动触发重新解析。你能想出更好的方法吗你有什么建议可以帮助我以正确的方式实现这样的功能吗?我知道这是性能的关键。我想找到在需要时重新解析脚本的最佳方法。我只能用两种方法中的一种。每X分钟重新解析一次或手动触发重新解析。你能想出更好的方法吗?或者你有什么建议可以帮助我实现这样的功能吗以适当的方式实现功能性?
import groovy.lang.*
import java.nio.file.*
import java.util.concurrent.locks.ReentrantLock

def source = new File('script.groovy')
def shell  = new GroovyShell()
def script = shell.parse(source.text)

def watchService = FileSystems.default.newWatchService()
source.canonicalFile.parentFile.toPath().register(watchService, StandardWatchEventKinds.ENTRY_MODIFY)

lock = new ReentrantLock()

boolean keepWatching = true 
Thread.start { 
  while (keepWatching) {
    def key = watchService.take()
    if (key.pollEvents()?.any { it.context() == source.toPath() }) {
      withLock { 
        script = shell.parse(source.text)
      }
      println "source reloaded..."
    }
    key.reset()
  }
}

def binding = new Binding()
def start = System.currentTimeMillis()
for (i=0; i<100; i++) {
  withLock { 
    script.setBinding(binding)
    def result = script.run()
    println "script ran: $result"
  }
  Thread.sleep(500)
} 
def delta = System.currentTimeMillis() - start
println "took ${delta}ms"

keepWatching = false

def withLock(Closure c) {
  def result
  lock.lock()
  try { 
    result = c()
  } finally { 
    lock.unlock()
  }
  result
}