Rhino性能和编译脚本
Rhino performance and compiled scripts
我有一些性能问题,因为在Rhino中执行Javascript代码很慢。
我编写了以下测试,以查看执行脚本的不同方式对性能的影响:
public class SimpleScriptsPerformanceTest {
private static int TIMES = 10000;
// no caching scope; without optimizations
@Test
public void testRhino1() {
Context ctx = Context.enter();
try {
ctx.setLanguageVersion(170);
ScriptableObject scriptScope = ctx.initStandardObjects();
long startTime = System.currentTimeMillis();
for (int i = 0; i < TIMES; i++) {
ctx.evaluateString(scriptScope, getScript1(), "script.js", 1, null);
}
long endTime = System.currentTimeMillis();
System.out.println("Total execution time (rhino1): " + (endTime-startTime) + "ms");
} catch (Exception e) {
e.printStackTrace();
} finally {
Context.exit();
}
}
// no caching scope; with optimizations
@Test
public void testRhino2() {
Context ctx = Context.enter();
try {
ctx.setOptimizationLevel(9);
ctx.setLanguageVersion(170);
ScriptableObject scriptScope = ctx.initStandardObjects();
long startTime = System.currentTimeMillis();
for (int i = 0; i < TIMES; i++) {
ctx.evaluateString(scriptScope, getScript1(), "script.js", 1, null);
}
long endTime = System.currentTimeMillis();
System.out.println("Total execution time (rhino2): " + (endTime-startTime) + "ms");
} catch (Exception e) {
e.printStackTrace();
} finally {
Context.exit();
}
}
// caching scope; with optimizations for main function and for calling code
@Test
public void testRhino3() {
Context ctx = Context.enter();
try {
ctx.setOptimizationLevel(9);
ctx.setLanguageVersion(170);
ScriptableObject scriptScope = ctx.initStandardObjects();
ctx.evaluateString(scriptScope, getScript1(), "script.js", 1, null);
ctx.setOptimizationLevel(9);
long startTime = System.currentTimeMillis();
for (int i = 0; i < TIMES; i++) {
ctx.evaluateString(scriptScope, getScript2(), "script.js", 1, null);
}
long endTime = System.currentTimeMillis();
System.out.println("Total execution time (rhino3): " + (endTime-startTime) + "ms");
} catch (Exception e) {
e.printStackTrace();
} finally {
Context.exit();
}
}
// caching scope; with optimizations for main function; no optimizations for calling code
@Test
public void testRhino4() {
Context ctx = Context.enter();
try {
ctx.setOptimizationLevel(9);
ctx.setLanguageVersion(170);
ScriptableObject scriptScope = ctx.initStandardObjects();
ctx.evaluateString(scriptScope, getScript1(), "script.js", 1, null);
ctx.setOptimizationLevel(-1);
long startTime = System.currentTimeMillis();
for (int i = 0; i < TIMES; i++) {
ctx.evaluateString(scriptScope, getScript2(), "script.js", 1, null);
}
long endTime = System.currentTimeMillis();
System.out.println("Total execution time (rhino4): " + (endTime-startTime) + "ms");
} catch (Exception e) {
e.printStackTrace();
} finally {
Context.exit();
}
}
// caching scope; without optimizations; different contexts
@Test
public void testRhino5() {
ScriptableObject scriptScope = null;
Context ctx = Context.enter();
try {
ctx.setOptimizationLevel(9);
ctx.setLanguageVersion(170);
scriptScope = ctx.initStandardObjects();
ctx.evaluateString(scriptScope, getScript1(), "script.js", 1, null);
} catch (Exception e) {
e.printStackTrace();
} finally {
Context.exit();
}
ctx = Context.enter();
try {
ctx.setOptimizationLevel(-1);
ctx.setLanguageVersion(170);
long startTime = System.currentTimeMillis();
for (int i = 0; i < TIMES; i++) {
ctx.evaluateString(scriptScope, getScript2(), "script.js", 1, null);
}
long endTime = System.currentTimeMillis();
System.out.println("Total execution time (rhino5): " + (endTime-startTime) + "ms");
} catch (Exception e) {
e.printStackTrace();
} finally {
Context.exit();
}
}
// script engine; eval
@Test
public void testScriptEngine1() throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
long startTime = System.currentTimeMillis();
for (int i = 0; i < TIMES; i++) {
engine.eval(getScript1());
}
long endTime = System.currentTimeMillis();
System.out.println("Total execution time (scriptEngine1): " + (endTime-startTime) + "ms");
}
// script engine; compiled script
@Test
public void testScriptEngine2() throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
Compilable compilingEngine = (Compilable)engine;
CompiledScript script = compilingEngine.compile(getScript1());
long startTime = System.currentTimeMillis();
for (int i = 0; i < TIMES; i++) {
script.eval();
}
long endTime = System.currentTimeMillis();
System.out.println("Total execution time (scriptEngine2): " + (endTime-startTime) + "ms");
}
private String getScript1() {
StringBuilder sb = new StringBuilder();
sb.append("var foo = function() {").append("'n");
sb.append(" var a = 5;").append("'n");
sb.append(" var b = 'test';").append("'n");
sb.append(" var c = 93.2;").append("'n");
sb.append(" var d = [];").append("'n");
sb.append(" for (var i = 0; i < 5; i++) {").append("'n");
sb.append(" if (i == 2) d.push('pepe');").append("'n");
sb.append(" else d.push('juan');").append("'n");
sb.append(" }").append("'n");
sb.append(" return res = a + b + c + d.join(',');").append("'n");
sb.append("}").append("'n");
sb.append("foo();").append("'n");
return sb.toString();
}
private String getScript2() {
StringBuilder sb = new StringBuilder();
sb.append("foo();").append("'n");
return sb.toString();
}
}
多次运行脚本后,我得到了以下平均时间:
Total execution time (rhino1): 8120 ms
Total execution time (rhino2): 7946 ms
Total execution time (rhino3): 4350 ms
Total execution time (rhino4): 257 ms
Total execution time (rhino5): 188 ms
Total execution time (scriptEngine1): 1547 ms
Total execution time (scriptEngine2): 1090 ms
所以rhino5似乎是上述最有效的,其中将函数'foo'放在作用域中只有一次,然后,在不同的上下文中,我在相同的作用域中调用该函数,根本没有优化。
从这些结果中,我得出以下结论:
- 库和实用程序方法应该在所有优化的作用域中运行。
- 缓存作用域,这样你就不需要再次解析脚本了。
- 当你运行一次性脚本时,不要使用优化。
- 不要使用ScriptEngine接口,因为它似乎比使用Rhino慢,即使使用编译脚本。
所以我的问题是:是否有一种方法可以更有效地运行Rhino脚本?
我有一些脚本不会经常更改(但确实更改并且需要在不停止应用程序的情况下更新它们),因此我可以编译和重用它们。然而,我不确定我正在做的(缓存和重用作用域)是最有效的方法。我看到有些人建议将Javascript编译成Java字节码,但不确定如何做到这一点。
指出:
- 我知道这不是做微基准测试的正确方法,但是结果非常一致,在这种情况下已经足够好了。
- 我无法切换到Java 8并使用Nashorn。
- 我确实在java7/Rhino中阅读了编译与解释javascript的性能
Rhino引擎实现了Compilable接口。我想这会比一直计算脚本字符串快得多。
Compilable compilingEngine = (Compilable) cEngine;
CompiledScript compiledScript = compilingEngine.compile(script);
相关文章:
- 浏览器是否持久缓存脚本元素的编译版本
- 使用脚本#编译代码(独立)
- 如何在删除脚本后刷新/重新编译dom中的脚本
- 使用NPM和Watchify编译多个脚本包
- in脚本未被编译
- 为什么这个咖啡脚本没有编译“;正确”;
- 让浏览器获取源代码并重新编译脚本以进行实时编辑
- 浏览器中常用脚本的预编译版本
- 节点应用程序自动重新加载,自动编译咖啡脚本和自动编译更少的css
- 咖啡脚本错误编译
- 编译咖啡脚本
- “尝试在清除的范围内运行编译和运行脚本” - 使用 Google Graph API 在 Drupal 中出错
- 使用npm脚本部分的webpack来编译es6
- Firefox控制台错误:试图在清除的范围内运行编译并执行脚本
- Babel Transforms不编译脚本
- 在Java编译的脚本中调用Javascript函数's编写API脚本
- Coffee脚本编译错误
- R.js不能正确编译模糊脚本
- 在Node脚本中加载预编译的把手栏模板
- 准备脚本在JavaScript编译器中编译(Google Closure)