2015-11-09 5 views
5

में एक विशिष्ट संदर्भ में फ़ंक्शन निष्पादित करना मेरे पास एक कस्टम नैशर्न रनटाइम है जिसे मैंने कुछ वैश्विक कार्यों और वस्तुओं के साथ स्थापित किया है - इनमें से कुछ स्टेटलेस हैं और इनमें से कुछ राज्यिक हैं। इस रनटाइम के खिलाफ, मैं कुछ कस्टम स्क्रिप्ट चला रहा हूं।नैशर्न

प्रत्येक निष्पादन के लिए, मैं एक नया संदर्भ कि वैश्विक संदर्भ के द्वारा समर्थित है बनाने पर योजना बना रहा हूँ:

myContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); 
engine.eval(myScript, myContext); 

मैं (क्या पढ़ा वैश्विक विस्तार करने के लिए, किसी भी संशोधन स्क्रिप्ट के नजरिए से के आधार पर) मेरे द्वारा बनाए गए नए संदर्भ तक ही सीमित होगा।

इन स्क्रिप्ट्स का मूल्यांकन करते समय, कुछ ऑब्जेक्ट्स (अच्छी तरह से परिभाषित नाम और विधि-नामों के साथ) का पर्दाफाश करते हैं। मैं engine से Invocable पर कास्टिंग करके ऑब्जेक्ट पर एक विधि का आह्वान कर सकता हूं। लेकिन मैं उस संदर्भ को कैसे जानूं जिसमें फ़ंक्शन चलाया जाएगा? क्या यह भी एक मुद्दा है, या उस फ़ंक्शन का निष्पादन संदर्भ उस संदर्भ के आधार पर स्थापित किया गया है जिसमें इसका मूल्यांकन किया गया था?

एक बहुप्रचारित स्थिति में मैं किस व्यवहार की अपेक्षा कर सकता हूं जहां सभी धागे एक ही स्क्रिप्ट-इंजन उदाहरण साझा करते हैं, और वे सभी एक ही स्क्रिप्ट (जो वैश्विक वस्तु का खुलासा करते हैं) चलाने की कोशिश करते हैं। जब मैं ऑब्जेक्ट पर विधि का आह्वान करता हूं, तो फ़ंक्शन किस संदर्भ में चलता है? ऑब्जेक्ट का किस उदाहरण का उपयोग करना है यह कैसे पता चलेगा?

मुझे invoke विधि देखने की उम्मीद थी जहां मैं संदर्भ निर्दिष्ट कर सकता हूं, लेकिन ऐसा लगता है कि यह मामला नहीं है। क्या ऐसा करने का कोई तरीका है, या क्या मैं इस बारे में पूरी तरह गलत हूं?

मुझे पता है कि इसके चारों ओर जाने का एक आसान तरीका प्रति निष्पादन के लिए एक नया स्क्रिप्ट-इंजन उदाहरण बनाना है, लेकिन जैसा कि मैं समझता हूं, मैं ऑप्टिमाइज़ेशन (विशेष रूप से साझा कोड पर) खो देता हूं। ऐसा कहा जा रहा है, यहां मदद से पहले संकलन करेगा?

+0

मैंने पढ़ा है कि प्री-कंपाइलिंग वास्तव में नैशर्न में नो-ऑप है इसलिए इससे मदद नहीं मिलती है। हालांकि स्रोत नहीं मिल रहा है। मै गलत हो सकता हूँ। –

उत्तर

9

मैंने इसे समझ लिया। समस्या मैं में चल रहा था कि invokeFunction एक NoSuchMethodException फेंक क्योंकि कार्यों कस्टम स्क्रिप्ट द्वारा उजागर इंजन के डिफ़ॉल्ट दायरे से बाइंडिंग में मौजूद नहीं था होगा:

ScriptContext context = new SimpleScriptContext(); 
context.setBindings(nashorn.createBindings(), ScriptContext.ENGINE_SCOPE); 
engine.eval(customScriptSource, context); 
((Invocable) engine).invokeFunction(name, args); //<- NoSuchMethodException thrown 

मैं बाहर खींच रहा था करना था तो क्या हुआ नाम से संदर्भ से समारोह और इतने की तरह स्पष्ट रूप से इसे कहते हैं:

JSObject function = (JSObject) context.getAttribute(name, ScriptContext.ENGINE_SCOPE); 
function.call(null, args); //call to JSObject#isFunction omitted brevity 

इस समारोह है कि अपने नए बनाए गए संदर्भ में मौजूद कॉल करेंगे। तुम भी वस्तुओं पर तरीकों इस तरह से आह्वान कर सकते हैं:

JSObject object = (JSObject) context.getAttribute(name, ScriptContext.ENGINE_SCOPE); 
JSObject method = (JSObject) object.getMember(name); 
method.call(object, args); 

call एक अनियंत्रित अपवाद फेंकता है (या तो Throwable एक RuntimeException या NashornException कि जावास्क्रिप्ट stackframe जानकारी के साथ शुरू कर दिया गया में लिपटे) ताकि आप स्पष्ट रूप से संभाल करने के लिए है कि हो सकता है अगर आप उपयोगी प्रतिक्रिया प्रदान करना चाहते हैं।

इस तरह धागे एक-दूसरे पर कदम नहीं उठा सकते हैं क्योंकि प्रति थ्रेड एक अलग संदर्भ है। मैं धागे के बीच कस्टम रनटाइम-कोड साझा करने में सक्षम था और यह सुनिश्चित करता हूं कि कस्टम-रनटाइम द्वारा प्रकट म्यूटेबल-ऑब्जेक्ट्स में राज्य परिवर्तन संदर्भ द्वारा अलग किए गए थे।

ऐसा करने के लिए, मैं एक CompiledScript उदाहरण है कि मेरे कस्टम क्रम-पुस्तकालय का एक संकलित प्रतिनिधित्व होता है बनाने के लिए:

public class Runtime { 

    private ScriptEngine engine; 
    private CompiledScript compiledRuntime; 

    public Runtime() { 
     engine = new NashornScriptEngineFactory().getScriptEngine("-strict"); 
     String source = new Scanner(
      this.getClass().getClassLoader().getResourceAsStream("runtime/runtime.js") 
     ).useDelimiter("\\Z").next(); 

     try { 
      compiledRuntime = ((Compilable) engine).compile(source); 
     } catch(ScriptException e) { 
      ... 
     } 
    } 

    ... 
} 

फिर जब मैं एक स्क्रिप्ट मैं संकलित स्रोत का मूल्यांकन पर अमल करने की जरूरत है, और उसके बाद का मूल्यांकन इस संदर्भ के खिलाफ स्क्रिप्ट के रूप में अच्छी तरह से:

ScriptContext context = new SimpleScriptContext(); 
context.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); 

//Exception handling omitted for brevity 

//Evaluate the compiled runtime in our new context 
compiledRuntime.eval(context); 

//Evaluate the source in the same context 
engine.eval(source, context); 

//Call a function 
JSObject jsObject = (JSObject) context.getAttribute(function, ScriptContext.ENGINE_SCOPE); 
jsObject.call(null, args); 

मैं इस एक से अधिक थ्रेड के साथ बाहर का परीक्षण किया और मुझे यकीन है कि राज्य में परिवर्तन संदर्भों है कि व्यक्ति धागे के हैं तक ही सीमित थे बनाने के लिए कर रहा था। ऐसा इसलिए है क्योंकि संकलित प्रतिनिधित्व को एक विशिष्ट संदर्भ में निष्पादित किया जाता है, जिसका अर्थ है कि इसके द्वारा प्रकट किए गए किसी भी चीज के उदाहरण उस संदर्भ में शामिल हैं।

यहां एक छोटा सा नुकसान यह है कि आप उन वस्तुओं के लिए ऑब्जेक्ट परिभाषाओं की अनावश्यक रूप से पुनर्मूल्यांकन कर सकते हैं जिनके पास थ्रेड-विशिष्ट स्थिति की आवश्यकता नहीं है। इस के आसपास पाने के लिए, सीधे इंजन पर इनका मूल्यांकन है, जो करने के लिए उन वस्तुओं के लिए बाइंडिंग जोड़ देगा इंजन के ENGINE_SCOPE:

:

public Runtime() { 
    ... 
    String shared = new Scanner(
     this.getClass().getClassLoader().getResourceAsStream("runtime/shared.js") 
    ).useDelimiter("\\Z").next(); 

    try { 
     ...   
     nashorn.eval(shared); 
     ... 
    } catch(ScriptException e) { 
     ... 
    } 
} 
बाद में

उसके बाद, आप इंजन के ENGINE_SCOPE से धागे की विशिष्ट संदर्भ पॉप्युलेट कर सकते हैं

context.getBindings(ScriptContext.ENGINE_SCOPE).putAll(engine.getBindings(ScriptContext.ENGINE_SCOPE)); 

एक चीज आपको करने की आवश्यकता होगी यह सुनिश्चित कर लें कि ऐसी कोई भी वस्तु जिसे आप बेनकाब करते हैं, जमे हुए हैं। अन्यथा उन्हें फिर से परिभाषित करना या गुण जोड़ना संभव है।

+2

अपने स्वयं के प्रश्न का उत्तर देने के लिए समय निकालने के लिए धन्यवाद। बहुत उपयोगी! हालांकि –

+0

प्रश्न हालांकि। संकलित लिपि और स्रोत का मूल्यांकन करने के बीच क्या अंतर है? ऐसा लगता है कि यह दोगुना है? –

+0

मैंने इस पर आधारित कार्यान्वित किया, लेकिन 'engine.eval (स्रोत, संदर्भ) 'छोड़ा और ऐसा लगता है कि यह ठीक काम कर रहा है। –

संबंधित मुद्दे