Java7でのRhinojavascriptエンジンのパフォーマンスに問題があります。まもなく、私のスクリプト(テキストを解析およびコンパイルする)は、Java7 Rhinoスクリプトエンジンでのスクリプトよりも約50〜100倍速くChromeで実行されます。
私は状況を改善する方法を見つけようとしていて、Rhinoがスクリプトのコンパイルをサポートしていることを発見しました。スクリプトを使って試してみましたが、実際には何の改善も見られませんでした。最後に-コンパイルされたバージョンと解釈されたバージョンのパフォーマンスに違いが見られないダミーの短いテストスイートになりました。私が間違っていることを教えてください。
注:一部のソースによると、Rhinoエンジンは、Javaで直接記述された「同じ」コードよりもコンパイルされたスクリプトの実行速度が約1.6遅くなります。このサンプルで使用されている「スクリプトのコンパイル」が、そこで想定されているものと同じであるかどうかはわかりません。
以下のJavaクラスのテストと、自分のマシンで取得したサンプル結果...
結果
com.sun.script.javascript.RhinoScriptEngine@c50443を介して実行しています..。 時間:886ms、文字:38890、合計:2046720 時間:760ms、文字:38890、合計:2046720 時間:725ms、文字:38890、合計:2046720 時間:765ms、文字:38890、合計:2046720 時間:742ms、文字:38890、合計:2046720 ...3918ms com.sun.script.javascript.RhinoCompiledScript @ b5c292 @ com.sun.script.javascript.RhinoScriptEngine @f92ab0..を介して実行 時間:813ms、文字:38890、合計:2046720 時間:805ms、文字:38890、合計:2046720 時間:812ms、文字:38890、合計:2046720 時間:834ms、文字:38890、合計:2046720 時間:807ms、文字:38890、合計:2046720 ...4101ms
Anon-Microからのコメント後に更新:
JavaScript eval()とcompile()の呼び出しをテストクラスでラップした後...
import sun.org.mozilla.javascript.internal.Context;
try {
Context cx = Context.enter();
cx.setOptimizationLevel(9);
cx.setLanguageVersion(170);
...
}
finally {
Context.exit();
}
結果は大幅に変化しました-平均1.8(テストクラスの新しいバージョン)秒から約150ミリ秒に。ただし、経由でロードされたScriptEngineから抽出されたdoTest()関数のインスタンスは、それがそうであると(CompiledScript = Compilable.compile()).eval(Bindings) -> Bindings.get("doTest")
言っておりsun.org.mozilla.javascript.internal.InterpretedFunction
、そのパフォーマンスは、コンパイル済みのバイトコードからロードされたJSのバージョン(Rhino 1.7r4による)よりもわずかに劣っています(約10%)-だから私はまだです舞台裏で実際に何が起こっているのかわからない。
1800ms - ScriptEngine.eval(), Optimization Level = default(-1?)
1758ms - CompiledScript, Optimization Level = default(-1?)
165ms - ScriptEngine.eval(), Optimization Level = 9
132ms - CompiledScript, Optimization Level = 9
116ms - compiled by Rhino 1.7r4 into bytecode class
PS:内部sunのパッケージ内のsun.org.mozilla.javascript.internal.Contextは、私にとって奇妙なデザインのように見えます-「internal」は、このクラスが開発者によって使用されないと想定されているため、「認定された」方法がないことを示しますJava7でJSエバリュエーターの最適化レベルを操作します。
テストクラス(更新、doTestCompiledは外部* .classからロードされます)
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleScriptContext;
import sun.org.mozilla.javascript.internal.Context;
import sun.org.mozilla.javascript.internal.Scriptable;
import sun.org.mozilla.javascript.internal.Function;
public class RhinoPerfTest4 {
final static ScriptEngineManager scm = new ScriptEngineManager();
final static String TEST_SCRIPT1 =
"function doTest() {\n"
+ " var scale = 5000, i, a = [], str, l, sum = 0,\n"
+ " start = (new Date()).getTime(), end;\n"
+ " for( i = 0; i < scale; i++ )\n"
+ " a.push(\"\" + i);\n"
+ " str = a.join(\"\");\n"
+ " l = str.length;\n"
+ " for( i = 0; i < l; i++ ) {\n"
+ " var c = str.charCodeAt(i);\n"
+ " if( c > 0)\n"
+ " sum += c;\n"
+ " }\n"
+ " end = (new Date()).getTime();\n"
+ "\n"
+ " // print(\" time: \" + (end - start) "
+ " + \"ms, chars: \" + l "
+ " + \", sum: \" + sum + \"\\n\");\n"
+ "}\n";
final static String TEST_SCRIPT2 =
"function doTest() {\n"
+ " var a = [], i;\n"
+ " for( i = 0; i < 500; i++ ) a.push(1);\n"
+ "}\n";
static class TestSet {
public int nCycles;
public String script;
public TestSet(int nCycles, String script) {
this.nCycles = nCycles;
this.script = script;
}
}
static TestSet set1 = new TestSet(5, TEST_SCRIPT1);
static TestSet set2 = new TestSet(500, TEST_SCRIPT2);
public static void main(String[] args) throws Exception {
ScriptEngine se;
int i;
long ts, te;
TestSet set = set1;
Object noArgs[] = new Object[]{};
try {
org.mozilla.javascript.Context mctx = org.mozilla.javascript.Context.enter();
se = scm.getEngineByExtension("js");
doTestCompiled doTestPreCompiled = new doTestCompiled();
org.mozilla.javascript.Scriptable scope = mctx.initStandardObjects();
doTestPreCompiled.call(mctx, scope, scope, null);
org.mozilla.javascript.Function doTest =
(org.mozilla.javascript.Function)scope.get("doTest", null);
for( int nHotSpot = 0; nHotSpot < 5; nHotSpot++ ) {
if( nHotSpot > 0 )
Thread.sleep(500);
ts = System.currentTimeMillis();
for( i = 0; i < set.nCycles; i++ ) {
doTest.call(mctx, scope, null, null);
}
te = System.currentTimeMillis();
System.out.println(" " + nHotSpot + ": " + (te - ts) + "ms");
}
}
finally {
org.mozilla.javascript.Context.exit();
}
for( int nOpt = 0; nOpt < 2; nOpt++ ) {
if( nOpt > 0 )
Thread.sleep(500);
Context cx = null;
try {
System.out.println("Cycle: " + nOpt);
cx = Context.enter();
if( nOpt > 0 ) {
System.out.println("OptLevel: " + 9);
cx.setOptimizationLevel(9);
cx.setLanguageVersion(170);
}
se = scm.getEngineByExtension("js");
se.eval(set.script);
System.out.println("\nRunning via " + se + " ... ");
Invocable invocable = (Invocable) se;
for( int nHotSpot = 0; nHotSpot < 5; nHotSpot++ ) {
if( nHotSpot > 0 )
Thread.sleep(500);
ts = System.currentTimeMillis();
for( i = 0; i < set.nCycles; i++ ) {
invocable.invokeFunction("doTest", noArgs);
}
te = System.currentTimeMillis();
System.out.println(" " + nHotSpot + ": " + (te - ts) + "ms");
}
se = scm.getEngineByExtension("js");
Compilable cse = (Compilable) se;
CompiledScript cs = cse.compile(set.script/* + "(doTest())"*/);
Scriptable scope = cx.initStandardObjects();
ScriptContext scriptContext = new SimpleScriptContext();
Bindings vars = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
cs.eval(vars);
Object odoTest = scriptContext.getAttribute("doTest");
Function doTest = (Function) vars.get("doTest");
System.out.println("\nRunning via " + cs + " @ " + se + " ... ");
for( int nHotSpot = 0; nHotSpot < 5; nHotSpot++ ) {
if( nHotSpot > 0 )
Thread.sleep(500);
ts = System.currentTimeMillis();
for( i = 0; i < set.nCycles; i++ ) {
doTest.call(cx, scope, null, noArgs);
}
te = System.currentTimeMillis();
System.out.println(" " + nHotSpot + ": " + (te - ts) + "ms");
}
}
finally {
if( cx != null )
Context.exit();
}
}
}
}