Post by Attila SzegediPost by Attila SzegediActually, 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.