2016-02-22 24 views
2

我最近一直在玩Play!框架和Nashorn試圖呈現Redux應用程序。最初,我在一個ThreadPoolExecutor中實現了多個Nashorn引擎,並在運行engine.eval()時使用了期貨。性能非常糟糕,我認爲是由於I/O高和我使用的阻塞未來。試圖使納順線程安全

變得更加熟悉Play!和他們的異步/承諾模式,我試圖重新開始只有一個ScriptEngine;每https://stackoverflow.com/a/30159424/5956783,腳本引擎本身是線程安全的,但綁定不是。這是在整體上類:

package services; 

import akka.actor.ActorSystem; 

import play.libs.F; 
import scala.concurrent.ExecutionContext; 

import java.io.FileReader; 


import javax.inject.Inject; 
import javax.inject.Singleton; 
import javax.script.*; 

@Singleton 
public class NashornEngine extends JSEngineAbstract { 

    private NashornThread engine; 
    private final ActorSystem actorSystem; 


    protected class NashornThread { 
     private ScriptEngine engine; 
     private final ExecutionContext executionContext = actorSystem.dispatchers().lookup("js-engine-executor"); 
     private CompiledScript compiledScript; 


     public NashornThread() { 
      try { 
       String dir = System.getProperty("user.dir"); 
       this.engine = new ScriptEngineManager(null).getEngineByName("nashorn"); 
       this.compiledScript = ((Compilable) this.engine).compile(new FileReader(dir + "/public/javascripts/bundle.js")); 
      } catch (Exception e) { 
       System.out.println(e.getMessage()); 
      } 
     } 

     public ScriptEngine getEngine() { 
      return engine; 
     } 

     public F.Promise<String> getContent(String path, String globalCode) { 
      return F.Promise.promise(() -> this.executeMethod(path, globalCode), this.executionContext); 
     } 

     private String executeMethod(String path, String json) throws ScriptException { 
      Bindings newBinding = engine.createBindings(); 
      try { 
       this.compiledScript.eval(newBinding); 
       getEngine().setBindings(newBinding, ScriptContext.ENGINE_SCOPE); 
       getEngine().eval("var global = this;"); 
       getEngine().eval("var console = {log: print, error: print, warn: print};"); 
       String result = getEngine().eval("App.renderApp('" + path + "', " + json + ")").toString(); 

       return result; 
      } catch(Exception e) { 
       e.printStackTrace(); 
       return null; 
      } 
     } 
    } 


    @Inject 
    public NashornEngine(ActorSystem actorSystem) { 
     this.actorSystem = actorSystem; 
     this.engine = new NashornThread(); 
    } 

    @Override 
    public F.Promise<String> getContent(String path, String globalCode) { 
     try { 
      F.Promise<String> result = engine.getContent(path, globalCode); 

      return result.map((String r) -> r); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 
} 

我的JavaScript應用出口的App對象與方法renderApp(path, state)可見。這其實確實工作,但只有16倍(是的,總是16)。與迭代17日開始,我得到下面的異常,並伴隨堆棧跟蹤:

java.lang.ClassCastException: jdk.nashorn.internal.objects.NativeRegExpExecResult cannot be cast to jdk.nashorn.internal.objects.NativeArray 
    at jdk.nashorn.internal.objects.NativeArray.getContinuousArrayDataCCE(NativeArray.java:1900) 
    at jdk.nashorn.internal.objects.NativeArray.popObject(NativeArray.java:937) 
    at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:660) 
    at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:228) 
    at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393) 
    at jdk.nashorn.internal.scripts.Script$Recompilation$23589$782286AA$\^eval\_.L:22918$L:22920$matchPattern(<eval>:23049) 
    at jdk.nashorn.internal.scripts.Script$Recompilation$23588$816752AAAAAA$\^eval\_.L:24077$L:24079$matchRouteDeep(<eval>:24168) 
    at jdk.nashorn.internal.scripts.Script$Recompilation$23587$820262DAA$\^eval\_.L:24077$L:24079$matchRoutes$L:24252$L:24253(<eval>:24254) 
    at jdk.nashorn.internal.scripts.Script$Recompilation$23586$809060$\^eval\_.L:23848$loopAsync$next(<eval>:23869) 
    at jdk.nashorn.internal.scripts.Script$Recompilation$23584$808906AAA$\^eval\_.L:23848$loopAsync(<eval>:23875) 
    at jdk.nashorn.internal.scripts.Script$Recompilation$23583$820189$\^eval\_.L:24077$L:24079$matchRoutes$L:24252(<eval>:24253) 
    at jdk.nashorn.internal.scripts.Script$Recompilation$23582$819862AAA$\^eval\_.L:24077$L:24079$matchRoutes(<eval>:24252) 
    at jdk.nashorn.internal.scripts.Script$Recompilation$23580$789440AA$\^eval\_.L:23151$L:23153$useRoutes$L:23209$match(<eval>:23239) 
    at jdk.nashorn.internal.scripts.Script$Recompilation$23518$847004AA$\^eval\_.L:25026$L:25028$match(<eval>:25084) 
    at jdk.nashorn.internal.scripts.Script$Recompilation$23468$3872AA$\^eval\_.L:53$renderApp(<eval>:147) 
    at jdk.nashorn.internal.scripts.Script$23467$\^eval\_.:program(<eval>:1) 
    at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:640) 
    at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:228) 
    at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393) 
    at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:446) 
    at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:403) 
    at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:399) 
    at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:155) 
    at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264) 
    at services.NashornEngine$NashornThread.executeMethod(NashornEngine.java:62) 
    at services.NashornEngine$NashornThread.lambda$getContent$0(NashornEngine.java:48) 
    at play.core.j.FPromiseHelper$$anonfun$promise$2.apply(FPromiseHelper.scala:36) 
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) 
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) 
    at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40) 
    at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:397) 
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) 
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) 
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) 
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) 

我的印象是,創建與編輯腳本一個新的綁定將作爲淨新的發動機下處理,但沒有按似乎並非如此。如果有什麼,我在這裏做錯了什麼?

我試圖使用Invocable以調用App對象上的方法,但這沒有什麼區別。

編輯 我在一個具有超線程的8核心機器上,這樣可以解釋失敗的第17次嘗試之前的16次成功嘗試。另外,我已經更新了executeMethod方法如下:

private String executeMethod(String path, String json) throws ScriptException { 
      Bindings newBinding = engine.createBindings(); 
      try { 
       this.compiledScript.eval(newBinding); 
       getEngine().eval("var global = this;", newBinding); 
       getEngine().eval("var console = {log: print, error: print, warn: print};", newBinding); 
       Object app = getEngine().eval("App", newBinding); 
       Invocable invEngine = (Invocable) getEngine(); 
       String result = invEngine.invokeMethod(app, "renderApp", path, json).toString(); 
//    String result = getEngine().eval("App.renderApp('" + path + "', " + json + ")", newBinding).toString(); 

       return result; 
      } catch(Exception e) { 
       e.printStackTrace(); 
       return null; 
      } 
     } 

回答

1

不幸的是,你在犀牛打了bug。好消息是它已經被修復了,修復程序在current early access releases

+0

是的!它的工作完美。謝謝! –

2

更新至最新版本的Nashorn或Java 1.8u76可解決此問題。