rorHandling(new
String[]{"-d","/home/guanbin","/home/guanbin/g.gv"}, true);
将g.gv编译为g.class
g.gv
PARAMS['name']='jack';将g.class反编译: javap -c -private -s g >
g.java
Compiled from "g.gv"public class g extends groovy.lang.Script{
public static transient boolean __$stMC; public static long
__timeStamp; public static long
__timeStamp__239_neverHappen1368583825046; public g(); public
g(groovy.lang.Binding); public static void
main(java.lang.String[]); public java.lang.Object run(); ........
public void super$3$println(java.lang.Object); public boolean
super$1$equals(java.lang.Object); public java.lang.Object
super$3$invokeMethod(java.lang.String, java.lang.Object); public
int super$1$hashCode(); static java.lang.Class
class$(java.lang.String);}
对于完成编译的class,会进行本地缓存,从而提高效率(key = script text, value = Class)
final ScriptEngineManager factory = new ScriptEngineManager();final
AtomicLong scriptCost = new AtomicLong();final long timeb =
System.currentTimeMillis();final AtomicLong count = new
AtomicLong();ExecutorService service =
Executors.newFixedThreadPool(11);for(int i = 0; i < 10; i)
service.execute(new Runnable() { @Override public void run() {
ScriptEngine engine = factory.getEngineByName("groovy"); // new
ScriptEngine obj, cache will expired while(true) { Map map = new
HashMap(); String prefix =
String.valueOf(System.nanoTime()).substring(5);//
engine.put("PARAMS_" prefix, map); // without cache
engine.put("PARAMS", map); // with cache for(int j = 0; j < 10;
j) {// String script =
String.format("PARAMS_%s['name_%s']='jack_%s';",prefix, prefix j,
prefix j); String script = "PARAMS['name']='jack';"; try {
count.incrementAndGet(); long b = System.nanoTime();
engine.eval_r(script); scriptCost.addAndGet(System.nanoTime()-b); }
catch (Exception e) { e.printStackTrace(); return; } } } }
});service.execute(new Runnable() { @Override public void run() {
while(true) { try { Thread.sleep(3000); } catch
(InterruptedException e) { e.printStackTrace(); } long costNano =
scriptCost.get(); long c = count.get(); long time =
System.currentTimeMillis()-timeb;
System.out.println(String.format("time:%s, count:%s, tps:%s,
average:%s", time, c, c*1000/time, costNano/c)); }
}});带cache:
time:6570503, count:82003860, tps:12480,
average:498863time:6573505, count:82040373, tps:12480,
average:498899cpu = 86%, load = 3.0
不带cache:
time:91847, count:5792, tps:63, average:156288377time:95113,
count:6058, tps:63, average:154671248time:98113, count:6238,
tps:63, average:155319788cpu = 97%, load = 2.5
clz cache map存在于GroovyScriptEngineImpl中(ManagedConcurrentMap
classMap)
而每次ScriptEngineFactory.getEngine("goovy")都会新构建一个GroovyScriptEngineImpl,于是cache失效,因此需要尽量重用ScriptEngine。
但是派克钢笔,ScriptEngine不是线程安全的。
AbstractScriptEngine -> SimpleScriptContext -> engineScope =
SimpleBindings -> map
通过scriptEngine.put(k,v)操作放入的数据,不可被多个线程同时访问
由于在web容器中,线程是复用的,应此将ScriptEngine作为ThreadLocal注入和获取,可以是一个解决方案。
GroovyScriptEngineImpl.eval_r(String script) { Class clz =
getFromMap(script); if(clz == null) clz =
GroovyClzLoader.parseClass(script); } Script obj =
clz.newInstance(); obj.setBinding(binding); obj.run();}
自定义GroovyClassLoader完成Class类的全局cache
public class CachedGroovyClassLoader extends GroovyClassLoader { //
script-string-to-generated Class map private static final Map();
private GroovyClassLoader proxyCL; public
CachedGroovyClassLoader(GroovyClassLoader proxyCL) { this.proxyCL =
proxyCL; } public Class