Discussion:
Threading Problem with Nashorn
Tobias Schlottke
2013-07-09 08:01:10 UTC
Permalink
Hi there,

we're currently planning to switch our infrastructure from Rhino to Nashorn but are experiencing some threading Issues that nobody addressed so far.
I tweeted with Jim Laskey and he kindly asked me to post it to this list.

Example:

https://gist.github.com/tobsch/5955518

Could could you check this example and check if this really is a problem in your eyes or if it is supposed to be this way?

Best,

Tobias
Attila Szegedi
2013-07-09 10:34:45 UTC
Permalink
Hi,

thanks for experimenting with Nashorn!

As far as your example is concerned, Nashorn is not thread safe by design. Indeed, if you evaluate

new NashornScriptEngineFactory().getParameter("THREADING")

it'll return null, which means "the engine implementation is not thread safe, and cannot be used to execute scripts concurrently on multiple threads" -- see <http://docs.oracle.com/javase/7/docs/api/javax/script/ScriptEngineFactory.html#getParameter(java.lang.String)>

Nashorn library internals themselves are thread safe to the degree that we're using synchronized and concurrent data structures for various internal static caches et cetera, but JavaScript programs executing within a single engine instance are not thread safe.

As I said, this is by design. ECMAScript 5.1 language specification doesn't define multithreading semantics for programs written in the language; they are inherently single threaded. If we were to make them thread safe, we'd be sacrificing single threaded performance for a behavior that falls outside of the specification. You can always create one script engine per thread using the same factory - that should work in a multithreaded scenario.

Actually, in your above example, since the JavaScript program has no explicit guarding of concurrent access to variable `i` you seem like you would actually even expect to have an engine that has "THREAD-ISOLATED" as its threading model instead of the simpler "MULTITHREADED" - that' very rare in an engine, usually hard to implement efficiently (do you clone all of the data up front? do you implement a copy-on-write semantics?) , and is functionally simpler to just have a non-threadsafe engine and let the users manage their own thread isolation by creating one engine instance per thread.

Cheers,
Attila.
Post by Tobias Schlottke
Hi there,
we're currently planning to switch our infrastructure from Rhino to Nashorn but are experiencing some threading Issues that nobody addressed so far.
I tweeted with Jim Laskey and he kindly asked me to post it to this list.
https://gist.github.com/tobsch/5955518
Could could you check this example and check if this really is a problem in your eyes or if it is supposed to be this way?
Best,
Tobias
Jim Laskey (Oracle)
2013-07-09 12:40:29 UTC
Permalink
That said, we are planning to support multiple threads using a worker model (post-JDK8.) The underlying mechanism used to implement workers is shipping with JDK8 (loadWithNewGlobal), so it will be possible to implement a similar model yourself. You can run the following with 'jjs -scripting':


var Executors = java.util.concurrent.Executors;
var TimeUnit = java.util.concurrent.TimeUnit;
var ArrayList = java.util.ArrayList;

var script = <<EOD
i = 0;
i += 1;
shortly_later = new Date()/1000 + Math.random;
while( (new Date()/1000) < shortly_later) { Math.random() };
i += 1;
EOD

function addition() {
return loadWithNewGlobal({ name: "addition", script: script });
}

var executor = Executors.newCachedThreadPool();
var results = new ArrayList();

for(var i = 0; i < 50; i++) {
// Clarify Runnable versus Callable
results.add(executor["submit(java.util.concurrent.Callable)"](addition));
}

var miscalculations = 0;
for each (var result in results) {
var jsResult = result.get().intValue();

if (jsResult != 2) {
print("Incorrect result from js, expected 1 + 1 = 2, but got " + jsResult);
miscalculations += 1;
}
}

executor.awaitTermination(1, TimeUnit.SECONDS);
executor.shutdownNow();

print("Overall: " + miscalculations + " wrong values for 1 + 1.");


Output:

Overall: 0 wrong values for 1 + 1.


Cheers,

-- Jim
Post by Attila Szegedi
Hi,
thanks for experimenting with Nashorn!
As far as your example is concerned, Nashorn is not thread safe by design. Indeed, if you evaluate
new NashornScriptEngineFactory().getParameter("THREADING")
it'll return null, which means "the engine implementation is not thread safe, and cannot be used to execute scripts concurrently on multiple threads" -- see <http://docs.oracle.com/javase/7/docs/api/javax/script/ScriptEngineFactory.html#getParameter(java.lang.String)>
Nashorn library internals themselves are thread safe to the degree that we're using synchronized and concurrent data structures for various internal static caches et cetera, but JavaScript programs executing within a single engine instance are not thread safe.
As I said, this is by design. ECMAScript 5.1 language specification doesn't define multithreading semantics for programs written in the language; they are inherently single threaded. If we were to make them thread safe, we'd be sacrificing single threaded performance for a behavior that falls outside of the specification. You can always create one script engine per thread using the same factory - that should work in a multithreaded scenario.
Actually, in your above example, since the JavaScript program has no explicit guarding of concurrent access to variable `i` you seem like you would actually even expect to have an engine that has "THREAD-ISOLATED" as its threading model instead of the simpler "MULTITHREADED" - that' very rare in an engine, usually hard to implement efficiently (do you clone all of the data up front? do you implement a copy-on-write semantics?) , and is functionally simpler to just have a non-threadsafe engine and let the users manage their own thread isolation by creating one engine instance per thread.
Cheers,
Attila.
Post by Tobias Schlottke
Hi there,
we're currently planning to switch our infrastructure from Rhino to Nashorn but are experiencing some threading Issues that nobody addressed so far.
I tweeted with Jim Laskey and he kindly asked me to post it to this list.
https://gist.github.com/tobsch/5955518
Could could you check this example and check if this really is a problem in your eyes or if it is supposed to be this way?
Best,
Tobias
Andrew Thompson
2013-07-13 14:51:56 UTC
Permalink
Post by Attila Szegedi
Actually, in your above example, since the JavaScript program has no explicit guarding of concurrent access to variable `i` you seem like you would actually even expect to have an engine that has "THREAD-ISOLATED" as its threading model instead of the simpler "MULTITHREADED" - that' very rare in an engine, usually hard to implement efficiently (do you clone all of the data up front? do you implement a copy-on-write semantics?) , and is functionally simpler to just have a non-threadsafe engine and let the users manage their own thread isolation by creating one engine instance per thread.
In a model like that, what' s the best way to manage state?

Assuming I want to make sure each invocation of eval() is unable to influence the next invocation - i.e. leave no ENGINE_SCOPE or GLOBAL_SCOPE behind between calls to eval, would it looks something like this:

ThreadLocal<ScriptEngine> engine = ...

ScriptContext sc = new SimpleScriptContext();

engine.get().eval(someScript, sc);

Is that a reasonable approach to getting isolation between eval() calls or is it overkill? Would creating new bindings be a better idea? This leaves leakage through GLOBAL_SCOPE but is GLOBAL_SCOPE visible to the JavaScript code?

ScriptEngine e = engine.get();
Bindings b = e.createBindings();
e.eval(someScript, b);

I am very interested in contrasting this with the worker model Jim Laskey posted about in the next message in this thread.


AndyT (lordpixel - the cat who walks through walls)
A little bigger on the inside

(see you later space cowboy, you can't take the sky from me)
Attila Szegedi
2013-07-13 17:18:28 UTC
Permalink
I believe that's a reasonable approach. The JavaScript "Global" object is actually ENGINE_SCOPE level state, so you should be fine.

Attila.
Post by Andrew Thompson
Post by Attila Szegedi
Actually, in your above example, since the JavaScript program has no explicit guarding of concurrent access to variable `i` you seem like you would actually even expect to have an engine that has "THREAD-ISOLATED" as its threading model instead of the simpler "MULTITHREADED" - that' very rare in an engine, usually hard to implement efficiently (do you clone all of the data up front? do you implement a copy-on-write semantics?) , and is functionally simpler to just have a non-threadsafe engine and let the users manage their own thread isolation by creating one engine instance per thread.
In a model like that, what' s the best way to manage state?
ThreadLocal<ScriptEngine> engine = ...
ScriptContext sc = new SimpleScriptContext();
engine.get().eval(someScript, sc);
Is that a reasonable approach to getting isolation between eval() calls or is it overkill? Would creating new bindings be a better idea? This leaves leakage through GLOBAL_SCOPE but is GLOBAL_SCOPE visible to the JavaScript code?
ScriptEngine e = engine.get();
Bindings b = e.createBindings();
e.eval(someScript, b);
I am very interested in contrasting this with the worker model Jim Laskey posted about in the next message in this thread.
AndyT (lordpixel - the cat who walks through walls)
A little bigger on the inside
(see you later space cowboy, you can't take the sky from me)
Benjamin Sieffert
2013-07-15 08:18:32 UTC
Permalink
Post by Attila Szegedi
Post by Attila Szegedi
Actually, in your above example, since the JavaScript program has no
explicit guarding of concurrent access to variable `i` you seem like you
would actually even expect to have an engine that has "THREAD-ISOLATED" as
its threading model instead of the simpler "MULTITHREADED" - that' very
rare in an engine, usually hard to implement efficiently (do you clone all
of the data up front? do you implement a copy-on-write semantics?) , and is
functionally simpler to just have a non-threadsafe engine and let the users
manage their own thread isolation by creating one engine instance per
thread.
In a model like that, what' s the best way to manage state?
Assuming I want to make sure each invocation of eval() is unable to
influence the next invocation - i.e. leave no ENGINE_SCOPE or GLOBAL_SCOPE
ThreadLocal<ScriptEngine> engine = ...
ScriptContext sc = new SimpleScriptContext();
engine.get().eval(someScript, sc);
Is that a reasonable approach to getting isolation between eval() calls or
is it overkill? Would creating new bindings be a better idea? This leaves
leakage through GLOBAL_SCOPE but is GLOBAL_SCOPE visible to the JavaScript
code?
ScriptEngine e = engine.get();
Bindings b = e.createBindings();
e.eval(someScript, b);
I am very interested in contrasting this with the worker model Jim Laskey
posted about in the next message in this thread.
AndyT (lordpixel - the cat who walks through walls)
A little bigger on the inside
(see you later space cowboy, you can't take the sky from me)
Hello,

I am working with Tobias on the project which inspired this topic and I'd
like to comment on your approaches and problems we found with them.
First, we'd really like to use CompiledScript, so in our case we tried a
ThreadLocal<CompiledScript>. As expected, this works correctly, though of
course leaves you with much overhead.
Concerning the second approach, we had little luck with using Bindings.
Iterating on the starting example again (
https://gist.github.com/tobsch/5955518), doing

public Double call() {
try {
SimpleBindings b = new SimpleBindings();
b.put("i", 0.0);
return (Double) onePlusOne.eval(b);
}

and removing "i = 0" from the javascript reproduces the same erronous
results.
Perhaps more interestingly (I noticed just yet, when adjusting the
example), writing

public Double call() {
try {
Bindings b = engine.createBindings();
b.put("i", 0.0);
return (Double) onePlusOne.eval(b);
}

results on "i" not being available to javascript. Passing empty bindings
and starting the script with "var i = 0" will solve this (js return value
has to be cast to Integer instead of Double then), but still yield
miscalculations.
This is, however, still using CompiledScript. Going your route and just
calling eval on the engine, passing the script and the bindings works
threadsafely.

Loading...