Rhino и одновременный доступ к javax.script.ScriptEngine - PullRequest
17 голосов
/ 04 февраля 2012

Я использую Rhino 1.6r2 через javax.script API. Я знаю, что движок Rhino заявляет, что он MULTITHREADED: «Реализация механизма внутренне поточно-ориентирована, и сценарии могут выполняться одновременно, хотя эффекты выполнения сценария в одном потоке могут быть видны сценариям в других потоках».

Что я хотел бы знать, так это то, при каких условиях эффекты выполнения одного скрипта будут видны другому? В моем коде я иногда повторно использую объект ScriptEngine, но для каждого выполнения я создаю новый SimpleBindings и передаю его eval(String, Bindings). При таком расположении, может ли внутреннее состояние просочиться из одного выполнения в другое? Если да, то как?

Здесь очень информативный ответ , но он не вполне говорит мне, что мне нужно знать.

Ответы [ 3 ]

4 голосов
/ 02 июля 2015

Пакет javax.script является поточно-ориентированным, но если ваш сценарий нет, у вас могут возникнуть проблемы с параллелизмом. Глобальные переменные внутри скрипта видны всем потокам. Итак, избегайте использования глобальных переменных внутри ваших функций JavaScript

Я сейчас сталкиваюсь с этой проблемой. Мой JavaScript-код выглядит следующим образом:

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

И я запускаю его внутри ThreadPool (4) 10.000 раз и печатаю результат.

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) {}
            }
        });
    }

Это часть вывода:

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
3 голосов
/ 01 марта 2012

Да, JSR223 не указывал, как переменные в языке сценариев должны быть связаны с данным Bindings. Поэтому вполне возможно, что разработчики выбирают хранение переменных глобальной области видимости в экземпляре движка и повторно используют его даже при разных Bindings при оценке скрипта.

Например, привязка JSR223 JRuby имеет один режим, работающий таким образом

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();
    }
}
0 голосов
/ 22 сентября 2018

Я изменил https://stackoverflow.com/a/1601465/22769 ответ, чтобы показать, что выполнение движка скрипта rhino полностью поточно безопасно, если вы зададите контекст в функции eval ().В примере вызывается fibonacci функция javascript 100 раз из 5 различных потоков одновременно:

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.");
    }   
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...