tutorial español engine java javascript rhino

español - Rhino y acceso simultáneo a javax.script.ScriptEngine



rhino javascript engine download (3)

Estoy usando Rhino 1.6r2 a través de la API javax.script . Sé que el motor de Rhino dice estar MULTITHREADED: "La implementación del motor es internamente segura para subprocesos y los scripts pueden ejecutarse simultáneamente, aunque los efectos de la ejecución del script en un hilo pueden ser visibles a los scripts en otros hilos".

Lo que me gustaría saber es, ¿bajo qué condiciones exactas los efectos de una ejecución de un script serían visibles para otro? En mi código, a veces reutilizo un objeto ScriptEngine , pero para cada ejecución creo un nuevo SimpleBindings y lo paso a eval(String, Bindings) . Con esta disposición, ¿hay alguna manera de que el estado interno pueda filtrarse de una ejecución a otra? ¿Si es así, cómo?

Aquí hay una respuesta muy informativa , pero no me dice lo que necesito saber.


El paquete javax.script es seguro para subprocesos, pero si su script no lo es, puede tener problemas de concurrencia. Las variables globales dentro de la secuencia de comandos son visibles para todos los subprocesos. Por lo tanto, evite utilizar variables globales dentro de sus funciones javascript.

Me estoy topando con este problema ahora mismo. Mi javascript es el siguiente:

function run(){ regex = 0; regex += 1; return regex; }

Y lo estoy ejecutando dentro de un ThreadPool (4) 10.000 veces, e imprimiendo el resultado.

for (int i = 0; i <= 10000; i++){ executor.submit(new Runnable() { @Override public void run() { try { Double result = (Double) invocable.invokeFunction("run"); System.out.println(result); } catch (Exception e) {} } }); }

Esta es una pieza de la salida:

1.0 2.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 2.0 1.0 1.0 0.0


Sí, JSR223 no especificó cómo se deberían vincular las variables en el lenguaje de script con los Bindings dados. Por lo tanto, es totalmente posible que los implementadores elijan almacenar variables de alcance global en la instancia del motor y reutilizarlo, incluso teniendo en cuenta los distintos Bindings al evaluar el script.

Por ejemplo, el enlace JSR223 de JRuby tiene un modo que funciona de esta manera

import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.script.SimpleScriptContext; public class Jsr223Binding { private Jsr223Binding() throws ScriptException { System.setProperty("org.jruby.embed.localvariable.behavior", "transient"); ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("jruby"); ScriptContext ctx1 = new SimpleScriptContext(); ScriptContext ctx2 = new SimpleScriptContext(); engine.eval("$foo = 5/nputs $foo", ctx1); engine.eval("puts $foo", ctx2); } public static void main(String[] args) throws ScriptException { new Jsr223Binding(); } }


https://.com/a/1601465/22769 respuesta https://.com/a/1601465/22769 para mostrar que la ejecución del motor de script rhino es completamente segura para subprocesos si especifica el contexto en la función eval (). El ejemplo llama a la función javascript de fibonacci 100 veces desde 5 hilos diferentes al mismo tiempo:

package samplethread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.script.SimpleScriptContext; public class JSRunner { private static final ScriptEngine engine; private static final ScriptEngineManager manager; private static final String script = "function fibonacci(num){/r/n" + " var a = 1, b = 0, temp;/r/n" + "/r/n" + " while (num >= 0){/r/n" + " temp = a;/r/n" + " a = a + b;/r/n" + " b = temp;/r/n" + " num--;/r/n" + " }/r/n" + "/r/n" + " return b;/r/n" + "} /r/n" + "var out = java.lang.System.out;/n" + "n = 1;" + "while( n <= 100 ) {" + " out.println(java.lang.Thread.currentThread().getName() +'':''+ ''FIB(''+ n +'') = '' + fibonacci(n));" + " n++;" + " if (java.lang.Thread.interrupted()) {" + " out.println(''JS: Interrupted::''+Date.now());" + " break;" + " }" + "}/n"; static { manager = new ScriptEngineManager(); engine = manager.getEngineByName("JavaScript"); } public static void main(final String... args) throws Exception { for(int i = 0;i<5;i++) { try { final Bindings b = engine.createBindings(); final SimpleScriptContext sc = new SimpleScriptContext(); sc.setBindings(b, ScriptContext.ENGINE_SCOPE); execWithFuture(engine, script,sc); } catch(Exception e) { e.printStackTrace(); } } } private static void execWithFuture(final ScriptEngine engine, final String script,final ScriptContext sc) throws Exception { System.out.println("Java: Submitting script eval to thread pool..."); ExecutorService single = Executors.newSingleThreadExecutor(); Callable<String> c = new Callable<String>() { public String call() throws Exception { String result = null; try { engine.eval(script,sc); } catch (ScriptException e) { result = e.getMessage(); } return result; } }; single.submit(c); single.shutdown(); System.out.println("Java: ...submitted."); } }