अवलोकन
भाषा X के लिए एक दुभाषिया एक प्रोग्राम (या मशीन, या सामान्य रूप से बस किसी प्रकार का तंत्र) है जो भाषा X में लिखे गए किसी भी प्रोग्राम p को निष्पादित करता है जैसे कि यह प्रभाव करता है और X के विनिर्देश द्वारा निर्धारित परिणामों का मूल्यांकन करता है । सीपीयू आमतौर पर अपने संबंधित निर्देशों के सेट के लिए व्याख्याकार होते हैं, हालांकि आधुनिक उच्च-प्रदर्शन कार्य केंद्र सीपीयू वास्तव में उससे अधिक जटिल हैं; उनके पास वास्तव में एक अंतर्निहित मालिकाना निजी अनुदेश सेट हो सकता है और या तो अनुवाद (संकलन) कर सकता है या बाहरी रूप से दृश्यमान सार्वजनिक अनुदेश सेट की व्याख्या कर सकता है।
एक संकलक से एक्स के लिए वाई एक प्रोग्राम (या एक मशीन, या सिर्फ सामान्य रूप में तंत्र के कुछ प्रकार) है कि किसी भी कार्यक्रम के लिए अनुवाद है पी कुछ भाषा से एक्स एक शब्दार्थ बराबर कार्यक्रम में पी ' कुछ भाषा में वाई इस तरह से है कि अर्थ विज्ञान कार्यक्रम संरक्षित हैं, यानी कि वाई के लिए एक दुभाषिया के साथ p, की व्याख्या करने से वही परिणाम प्राप्त होंगे और X के लिए दुभाषिया के साथ p की व्याख्या करने के समान प्रभाव होंगे । (ध्यान दें कि X और Y एक ही भाषा हो सकती है।)
मामले आगे के- समय (AOT) और जस्ट-इन-टाइम (JIT) का उल्लेख है जब संकलन जगह लेता है: "समय" उन शब्दों में निर्दिष्ट "क्रम", है यानी एक JIT कम्पाइलर प्रोग्राम को संकलित रूप में यह है चलने से पहले AOT कंपाइलर प्रोग्राम को कंपाइल करता है । ध्यान दें कि इसके लिए यह आवश्यक है कि भाषा X से भाषा Y तक JIT संकलक किसी तरह भाषा Y के लिए दुभाषिया के साथ मिलकर काम करेंअन्यथा, कार्यक्रम को चलाने का कोई तरीका नहीं होगा। (इसलिए, उदाहरण के लिए, एक JIT संकलक जो जावास्क्रिप्ट को x86 मशीन कोड के लिए संकलित करता है, एक x86 CPU के बिना कोई मतलब नहीं है; यह प्रोग्राम को चलाने के दौरान संकलित करता है, लेकिन x86 CPU के बिना यह प्रोग्राम चालू नहीं होगा।)
ध्यान दें कि यह अंतर दुभाषियों के लिए कोई मतलब नहीं है: एक दुभाषिया कार्यक्रम चलाता है। एओटी दुभाषिया का विचार जो चलने से पहले एक कार्यक्रम चलाता है या एक जेआईटी दुभाषिया जो एक कार्यक्रम चलाता है, जबकि यह निरर्थक है।
तो हमारे पास:
- एओटी कंपाइलर: चलने से पहले कंपाइल करता है
- JIT कंपाइलर: कंपाइल करते समय
- दुभाषिया: चलाता है
जेआईटी कंपाइलर
जेआईटी संकलक के परिवार के भीतर, अभी भी कई अंतर हैं जैसे वे वास्तव में संकलित करते हैं, कितनी बार , और किस ग्रैन्युलैरिटी पर।
Microsoft के CLR में JIT कंपाइलर केवल एक बार कोड (जब यह लोड होता है) को संकलित करता है और एक बार में पूरी असेंबली को संकलित करता है। जब प्रोग्राम चल रहा हो तो अन्य कंपाइलर जानकारी एकत्र कर सकते हैं और कोड को कई बार फिर से जमा कर सकते हैं क्योंकि नई जानकारी उपलब्ध हो जाती है जो उन्हें बेहतर अनुकूलन करने की अनुमति देती है। कुछ JIT कंपाइलर भी कोड को डी-ऑप्टिमाइज़ करने में सक्षम हैं । अब, आप अपने आप से पूछ सकते हैं कि कोई ऐसा क्यों करना चाहेगा? डी-ऑप्टिमाइज़िंग आपको बहुत आक्रामक अनुकूलन करने की अनुमति देता है जो वास्तव में असुरक्षित हो सकता है: अगर यह पता चला कि आप बहुत आक्रामक थे तो आप बस फिर से वापस कर सकते हैं, जबकि, जेआईटी संकलक जो डी-ऑप्टिमाइज़ नहीं कर सकता है, आप नहीं चला सकते थे। पहले स्थान पर आक्रामक अनुकूलन।
JIT कंपाइलर एक बार (एक मॉड्यूल, एक वर्ग, एक फ़ंक्शन, एक विधि, ...) में कोड की कुछ स्थिर इकाई को संकलित कर सकते हैं, इन्हें आम तौर पर विधि-ए-टाइम JIT कहा जाता है , उदाहरण के लिए या वे डायनामिक का पता लगा सकते हैं डायनेमिक ट्रैस (आमतौर पर लूप) को खोजने के लिए कोड का निष्पादन, जिसे वे तब संकलित करेंगे (इन्हें ट्रेसिंग जेआईटी कहा जाता है )।
इंटरप्रेन्योर और कंपाइलर का मेल
दुभाषियों और संकलक को एकल भाषा निष्पादन इंजन में जोड़ा जा सकता है। दो विशिष्ट परिदृश्य हैं जहां यह किया जाता है।
से एक AOT संकलक का मेल एक्स के लिए वाई के लिए एक अनुवादक के साथ वाई । यहाँ, आमतौर पर X मनुष्यों द्वारा पठनीयता के लिए अनुकूलित कुछ उच्च-स्तरीय भाषा है, जबकि Yमशीनों द्वारा व्याख्या के लिए अनुकूलित एक कॉम्पैक्ट भाषा (अक्सर किसी प्रकार का बायटेकोड) है। उदाहरण के लिए, CPython Python निष्पादन इंजन में AOT कंपाइलर है जो Python sourcecode को CPython bytecode और एक दुभाषिया है जो CPython bytecode की व्याख्या करता है। इसी तरह, YARV रूबी के निष्पादन इंजन में AOT कंपाइलर है जो YARV bytecode को Ruby sourcecode और YARV bytecode की व्याख्या करने वाला दुभाषिया संकलित करता है। आप ऐसा क्यों करना चाहते हो? रूबी और पायथन दोनों बहुत उच्च-स्तरीय और कुछ हद तक जटिल भाषाएं हैं, इसलिए हम पहले उन्हें एक ऐसी भाषा में संकलित करते हैं जो पार्स करना आसान है और व्याख्या करना आसान है, और फिर उस भाषा की व्याख्या करें ।
दुभाषिया और संकलक को मिलाने का दूसरा तरीका मिश्रित-मोड निष्पादन इंजन है। यहां, हम एक ही भाषा को एक साथ लागू करने के "दो" मोड " , एक्स के लिए एक दुभाषिया और एक्स से वाई तक एक जेआईटी संकलक हैं ।" (इसलिए, यहां अंतर यह है कि उपरोक्त मामले में, हमारे पास प्रोग्राम को संकलित करने और फिर दुभाषिया में परिणाम को फीड करने के साथ कई "चरण" थे, यहां हमारे पास एक ही भाषा पर दो कार्य -पक्ष हैं। ) कोड जो एक संकलक द्वारा संकलित किया गया है, एक दुभाषिया द्वारा निष्पादित कोड की तुलना में तेज़ी से चलने के लिए है, लेकिन वास्तव में कोड को संकलित करने में पहले समय लगता है (और विशेष रूप से, यदि आप कोड को चलाने के लिए भारी अनुकूलन करना चाहते हैं।वास्तव में तेजी से, इसमें बहुत समय लगता है)। इसलिए, इस समय को पार करने के लिए जहां जेआईटी कंपाइलर कोड संकलित करने में व्यस्त है, दुभाषिया पहले से ही कोड चलाना शुरू कर सकता है, और जेआईटी कंपाइलिंग समाप्त होने के बाद, हम निष्पादन को संकलित कोड पर स्विच कर सकते हैं। इसका मतलब है कि हम दोनों को संकलित कोड का सर्वोत्तम संभव प्रदर्शन मिलता है, लेकिन हमें संकलन समाप्त करने के लिए इंतजार नहीं करना पड़ता है, और हमारा आवेदन सीधे चलना शुरू होता है (हालांकि जितना तेज़ हो सकता है उतना नहीं है)।
यह वास्तव में मिश्रित-मोड निष्पादन इंजन का केवल सबसे सरल संभव अनुप्रयोग है। अधिक दिलचस्प संभावनाएं हैं, उदाहरण के लिए, तुरंत संकलन शुरू नहीं करने के लिए, लेकिन दुभाषिया को थोड़ा सा चलने दें, और आंकड़े इकट्ठा करें, प्रोफाइलिंग जानकारी, प्रकार की जानकारी, जानकारी की संभावना के बारे में कि कौन से विशिष्ट सशर्त शाखाएं ली गई हैं, कौन से तरीके कहलाते हैं सबसे अधिक बार आदि और फिर इस गतिशील जानकारी को संकलक को खिलाएं ताकि यह अधिक अनुकूलित कोड उत्पन्न कर सके। यह डी-ऑप्टिमाइज़ेशन को लागू करने का एक तरीका भी है जिसके बारे में मैंने ऊपर बात की है: यदि यह पता चला है कि आप अनुकूलन में बहुत आक्रामक थे, तो आप कोड को फेंक सकते हैं (कोड का एक हिस्सा) और व्याख्या करने के लिए वापस लौट सकते हैं। उदाहरण के लिए, हॉटस्पॉट JVM ऐसा करता है। इसमें जेवीएम बायटेकोड के साथ-साथ जेवीएम बायटेकोड के लिए एक संकलक दोनों शामिल हैं। (असल में,दो संकलक;)
यह भी संभव है और वास्तव में उन दो दृष्टिकोणों को संयोजित करने के लिए आम है: दो चरणों में पहला एओटी संकलक होता है जो एक्स से वाई और दूसरे चरण में मिश्रित-मोड इंजन होता है जो वाई की व्याख्या करता है और वाई से जेड को संकलित करता है । रुबिनियस रूबी निष्पादन इंजन इस तरह से काम करता है, उदाहरण के लिए: इसमें एक एओटी कंपाइलर है जो रूबिनस बायटेकोड को रूबी सोर्सकोड और एक मिश्रित-मोड इंजन को संकलित करता है जो पहले रुबिनस बायटेकोड की व्याख्या करता है और एक बार जब यह कुछ जानकारी एकत्र करता है, तो मूल में सबसे अधिक बार बुलाए जाने वाले तरीकों को संकलित करता है। मशीन कोड।
ध्यान दें कि एक मिश्रित-मोड निष्पादन इंजन के मामले में दुभाषिया की भूमिका, अर्थात् तेजी से स्टार्टअप प्रदान करना, और संभावित रूप से जानकारी एकत्र करना और वैकल्पिक रूप से कमबैक क्षमता प्रदान करना भी एक दूसरे JIT कंपाइलर द्वारा खेला जा सकता है। उदाहरण के लिए, V8 कैसे काम करता है। V8 कभी व्याख्या नहीं करता है, यह हमेशा संकलन करता है। पहला कंपाइलर एक बहुत तेज, बहुत पतला कंपाइलर है जो बहुत जल्दी शुरू होता है। हालांकि यह जो कोड तैयार करता है वह बहुत तेज़ नहीं है। यह कंपाइलर उस कोड में प्रोफाइलिंग कोड को भी इंजेक्ट करता है जो इसे उत्पन्न करता है। अन्य संकलक धीमा है और अधिक मेमोरी का उपयोग करता है, लेकिन बहुत तेज़ कोड का उत्पादन करता है, और यह पहले संकलक द्वारा संकलित कोड को चलाकर एकत्र की गई जानकारी का उपयोग कर सकता है।