我应该为每个线程使用单独的ScriptEngine和CompiledScript实例吗? [英] Should I use a separate ScriptEngine and CompiledScript instances per each thread?

查看:1471
本文介绍了我应该为每个线程使用单独的ScriptEngine和CompiledScript实例吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的程序使用Java Scripting API并且可以同时评估一些脚本。它们不使用共享脚本对象,Bindings或Context,但可以使用相同的 ScriptEngine CompiledScript 对象。我看到Java 8中的Oracle Nashorn实现不是多线程的, ScriptEngineFactory.getParameter('THREADING')返回 null about文档说:

My program uses Java Scripting API and can eval some scripts concurrently. They don't use shared script objects, Bindings or Context, but can use same ScriptEngine and CompiledScript objects. I see that Oracle Nashorn implementation in Java 8 is not multithreaded, ScriptEngineFactory.getParameter('THREADING') returns null about which the documentation says:


引擎实现不是线程安全的,并且不能用于
在多个线程上并发执行脚本。

The engine implementation is not thread safe, and cannot be used to execute scripts concurrently on multiple threads.

这是否意味着我应该创建一个单独的 ScriptEngine 实例每个线程?
此外,文档没有提及 CompiledScript 并发使用但是:

Does it mean that I should create a separate instance of ScriptEngine for each thread? Besides, documentation says nothing about CompiledScript concurrent usage but:


每个CompiledScript都与ScriptEngine相关联

Each CompiledScript is associated with a ScriptEngine

可以假设 CompiledScript 主题-safety依赖于相关的 ScriptEngine ,即我应该为Nashorn的每个线程使用单独的 CompiledScript 实例。

It can be assumed that CompiledScript thread-safety depends on related ScriptEngine, i.e. I should use separate CompiledScript instance for each thread with Nashorn.

如果我应该,对于这个(我认为很常见)的情况,使用 ThreadLocal ,一个池或什么的适当的解决方案是什么?否?

If I should, what is the appropriate solution for this (I think very common) case, using ThreadLocal, a pool or something else?

final String script = "...";
final CompiledScript compiled = ((Compilable)scriptEngine).compile(script);
for (int i=0; i<50; i++) {
    Thread thread = new Thread () {
        public void run() {
            try {
                scriptEngine.eval(script, new SimpleBindings ());  //is this code thread-safe?
                compiled.eval(new SimpleBindings ());  //and this?
            }
            catch (Exception e)  {  throw new RuntimeException (e);  }
        }
    };
    threads.start();
}


推荐答案

您可以分享 ScriptEngine CompiledScript 跨线程的对象。它们是线程安全的。实际上,你应该共享它们,因为单个引擎实例是类缓存和JavaScript对象的隐藏类的持有者,所以只有一个你减少重复编译。

You can share a ScriptEngine and CompiledScript objects across threads. They are threadsafe. Actually, you should share them, as a single engine instance is a holder for a class cache and for JavaScript objects' hidden classes, so by having only one you cut down on repeated compilation.

你不能分享的是 Bindings 对象。绑定对象基本上对应于JavaScript运行时环境的全局对象。引擎以默认绑定实例启动,但如果在多线程环境中使用它,则需要使用 engine.createBindings()为每个线程获取单独的Bindings对象 - - 它自己的全局,并将编译的脚本评估到其中。这样,您将使用相同的代码设置隔离的全局范围。 (当然,您也可以对它们进行池化,或者在它们上进行同步,只需确保在一个绑定实例中永远不会有多个线程工作)。一旦您将脚本评估为绑定,您随后可以有效地调用它使用定义的函数((JSObject)bindings.get(fnName).call(this,args ...)

What you can't share is Bindings objects. The bindings object basically corresponds to the JavaScript runtime environment's Global object. The engine starts with a default bindings instance, but if you use it in multithreaded environment, you need to use engine.createBindings() to obtain a separate Bindings object for every thread -- its own global, and evaluate the compiled scripts into it. That way you'll set up isolated global scopes with the same code. (Of course, you can also pool them, or synchronize on 'em, just make sure there's never more than one thread working in one bindings instance). Once you evaluated the script into the bindings, you can subsequently efficiently invoke functions it defined with ((JSObject)bindings.get(fnName).call(this, args...)

如果必须跨线程共享状态,那么至少尝试使其不可变。如果你的对象是不可变的,你也可以将脚本评估为单个 Bindings 实例然后只使用它跨线程(调用有希望的副作用免费函数)。如果它是可变的,你将必须同步;要么是整个绑定,要么你也可以使用 var syncFn = Java.synchronized(fn,lockObj) Nashorn特定的JS API来获取在特定对象上同步的JS函数版本。

If you must share state across threads, then at least try to make it not mutable. If your objects are immutable, you might as well evaluate the script into single Bindings instance and then just use that across threads (invoking hopefully side-effect free functions). If it is mutable, you'll have to synchronize; either the whole bindings, or you can also use the var syncFn = Java.synchronized(fn, lockObj) Nashorn-specific JS API to obtain versions of JS functions that synchronize on a specific object.

这预先假定你在线程之间共享单个绑定。如果你想让多个绑定共享一个对象的子集(例如,通过将同一个对象放入多个绑定中),再次,你将会必须以某种方式处理确保访问共享对象本身就是线程安全的。

This presupposes that you share single bindings across threads. If you want to have multiple bindings share a subset of objects (e.g. by putting the same object into multiple bindings), again, you'll have to somehow deal with ensuring that access to shared objects is thread safe yourself.

至于 THREADING 参数返回null :是的,最初我们计划不使引擎线程安全(说语言本身不是线程安全的)所以我们选择了null值。我们现在可能需要重新评估,因为在此期间我们确实使得引擎实例是线程安全的,只是全局范围(绑定)不是(并且永远不会,因为JavaScript语言语义。)

As for THREADING parameter returning null: yeah, initially we planned on not making the engine threadsafe (saying that the language itself isn't threadsafe) so we chose the null value. We might need to re-evaluate that now, as in the meantime we did make it so that engine instances are threadsafe, just the global scope (bindings) isn't (and never will be, because of JavaScript language semantics.)

这篇关于我应该为每个线程使用单独的ScriptEngine和CompiledScript实例吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆