Hi Benjamin -- thanks for your response. Interesting approach tho not sure if it'll work for my situation. A couple of questions:
> *Any one of these scripts gets evaluated by the engine once and the returned ScriptObjectMirror* Do these ScriptObjectMirror objects have your library in scope somehow? That is, if you load library into the engine, then eval() a secondary script to get a ScriptObjectMirror, how can you call a function on it via callMember() if that function leverages functions/obj/props of the library? > *To get nice stack traces, we also wrap each small javascript into a load()-call in the engine and name it. The library is also wrapped in a load()-call.* Not clear to me. Any chance you could share a code snippet? thanks for your time and thoughts! On Thu, Oct 30, 2014 at 10:03 AM, Benjamin Sieffert < [email protected]> wrote: > Hello there, > > we had a similar aim / similar issues with nashorn. Since I don't know > your code exactly, I'll just describe our case / what we ended up doing and > maybe you can get some ideas off that. > > We use one ScriptEngine. Among all our threads, just one engine. On > start-up we let it compile the library once. The library has no mutable > state and is not dependant on global variables. It's just a collection of > functions / classes. > Then we have a few hundred small javascripts that basically instantiate a > class defined by the library and do some configurations on that instance. > Any one of these scripts gets evaluated by the engine once and the returned > ScriptObjectMirror (the configured javascript object) is then kept on the > java side. As this ScriptObjectMirror also does not have any mutable state, > we can now safely use it among multiple threads via callMember(). > To get nice stack traces, we also wrap each small javascript into a > load()-call in the engine and name it. The library is also wrapped in a > load()-call. > > All approaches including some sort of mutable javascript-side state sadly > do not seem to be workable. The nashorn devs have (understandably) > explicitly stated that since javascript does not define multithreaded > semantics, they will not be implementing any. > Everything evaluated in a NashornScriptEngine keeps its original > context/global, even when seemingly "put" into another engine. You cannot > prevent pollution. I tried for some time. : ) > > Regards > > On 30 October 2014 14:09, yikes aroni <[email protected]> wrote: > >> Hi ... I’m using nashorn by embedding it in Java (not via command-line). I >> can make it work, but I have a two primary challenges: 1) speed of >> execution; and 2) thread safety. >> >> >> >> I have a “base” JS library that I compile more or less like this: >> >> >> >> ScriptEngineManager *factory* = *new* ScriptEngineManager(); >> >> ScriptEngine *baseEngine* = *factory*.getEngineByName("nashorn"); >> >> Compilable *baseCompilable* = (Compilable) *baseEngine*; >> >> baseCompilable.compile(*new* java.io.FileReader(*pathDsBase*)).eval(); >> >> >> >> where *pathDsBase* is a file system path to my javascript library. This >> library isn’t huge, but it takes about 500+ ms to compile and eval(). >> That’s a long time for my purposes, so I want to do it only once. >> >> >> >> Other parts of my code then launch multiple Java threads that do various >> work and occasionally invoke small, “temporary” Javascript scripts that >> need to reference objects and functions in this “base” library. Since I >> want these small scripts to run fast and thread-safe, I **could** simply >> create a brand new ScriptEngine every time I want to run one of these >> small, “temporary” scripts and recompile the base library into it. Problem >> with that is that it takes too much time. >> >> >> >> I’ve tried a lot of approaches -- none have worked. >> >> >> >> My main approach (which has failed miserably at every turn) is to create a >> “base” ScriptEngine, compile the “base” library into it, then create a >> “temporary” ScriptEngine and attempt to set the base bindings / context >> to >> it so that the temp ScriptEngine only eval()s the “temp” script, but has >> the base library in scope. For example something like this test code: >> >> >> >> ScriptEngine tempEngine = engineFactory.getScriptEngine(); // a >> temporary engine. This is the one that will evaluate the “small” scripts >> that reference the “base” script library. >> >> ScriptContext ctxBase = *new* SimpleScriptContext(); >> >> ctxBase.setBindings(baseEngine.createBindings(), ScriptContext. >> *GLOBAL_SCOPE*); >> >> // evaluate a script at add it to base’s context. This is where the >> “base” script libraries would be eval()-ed into the baseEngine context. >> >> baseEngine.eval("var y = 'hello';", ctxBase); >> >> >> >> // Now attempt to set the baseEngine’s bindings (which I >> assume have y = “hello” in them (since I’m not clear where they end up, >> I’ve tried every possible combination or ENGINE and GLOBAL scope.) >> >> ScriptContext ctxTemp = *new* SimpleScriptContext(); >> >> ctxTemp.setBindings(baseEngine.createBindings(), ScriptContext. >> *ENGINE_SCOPE*); >> >> >> >> // Now for the temporary, “small” script. The print references a >> variable (y) that I had hoped would be set to the temp engine’s scope from >> the “base” engine’s context. >> >> String script = "var x = 'world'; print(y + x);"; >> >> tempEngine.eval(script, ctxTemp); >> >> >> >> Exception is Exception in thread "main" *javax.script.ScriptException*: >> ReferenceError: "y" is not defined in <eval> at line number 1 >> >> >> >> I’ve also tried using loadWithNewGlobal, which solves the threading issue, >> but doesn’t appear to solve the speed issue: the script has to be >> recompiled every time. >> >> >> >> I am sure I am barking up the wrong tree. Can somebody help point me in >> the >> right direction for how to do this? Again, my two primary questions are: >> >> >> >> 1) (Speed) Generally, how do I make it so that I don’t have to re-eval() a >> large library every time I want to run a script that references it? Or, >> more specifically, how can I reuse code compiled (eval()ed) by one engine >> (“base”) in another engine (“temp”)? >> >> 2) (Thread-safety) How do I reuse such a library in a way that running the >> subsequent “temp” scripts doesn’t pollute the “base” bindings that I’m >> reusing? >> >> >> >> I will be overjoyed if there is a clean solution to this. If not, I will >> still be happy to clear up this mystery with a “can’t do that...” if that >> is, in fact, the answer.... >> >> >> >> thanks >> > > > > -- > Benjamin Sieffert > metrigo GmbH > Sternstr. 106 > 20357 Hamburg > > Geschäftsführer: Christian Müller, Tobias Schlottke, Philipp Westermeyer, > Martin Rieß > Die Gesellschaft ist eingetragen beim Registergericht Hamburg > Nr. HRB 120447. >
