थ्रेडेड कोड
कंप्यूटर विज्ञान में, थ्रेडेड कोड एक प्रोग्रामिंग तकनीक है जहां स्रोत कोड का एक रूप होता है जो अनिवार्य रूप से पूरी तरह से सबरूटीन्स को कॉल करता है। यह अक्सर संकलक्स में प्रयोग किया जाता है, जो उस रूप में कोड उत्पन्न कर सकता है या स्वयं उस रूप में कार्यान्वित किया जा सकता है। कोड को दुभाषिया (कंप्यूटिंग) द्वारा संसाधित किया जा सकता है या यह केवल मशीन कोड कॉल निर्देशों का अनुक्रम हो सकता है।
थ्रेडेड कोड में वैकल्पिक पीढ़ी तकनीकों और वैकल्पिक कॉलिंग सम्मेलनों द्वारा उत्पन्न कोड की तुलना में बेहतर कोड घनत्व होता है। कैश (कंप्यूटिंग) आर्किटेक्चर में, यह निष्पादन (कंप्यूटिंग) थोड़ा धीमा हो सकता है।[citation needed] हालाँकि, एक प्रोग्राम जो एक कंप्यूटर प्रोसेसर के CPU कैश में फिट होने के लिए काफी छोटा है, एक बड़े प्रोग्राम की तुलना में तेजी से चल सकता है जो कई कैश मिस से ग्रस्त है।[1] धागा स्विचिंग पर छोटे प्रोग्राम भी तेज़ हो सकते हैं, जब अन्य प्रोग्राम कैश भर चुके हों।
थ्रेडेड कोड को प्रोग्रामिंग भाषा के कई कंपाइलरों में इसके उपयोग के लिए जाना जाता है, जैसे फोर्थ (प्रोग्रामिंग भाषा), बुनियादी के कई कार्यान्वयन, COBOL के कुछ कार्यान्वयन, B के शुरुआती संस्करण (प्रोग्रामिंग लैंग्वेज),[2] और छोटे मिनी कंप्यूटर और शौकिया रेडियो उपग्रहों के लिए अन्य भाषाएं।[citation needed]
इतिहास
This section possibly contains original research. (February 2020) (Learn how and when to remove this template message) |
कंप्यूटर प्रोग्राम बनाने का सामान्य तरीका मशीन कोड में स्रोत कोड (कुछ प्रतीकात्मक भाषा (प्रोग्रामिंग) में लिखा गया) का अनुवाद करने के लिए एक कंपाइलर का उपयोग करना है। परिणामी निष्पादन योग्य आमतौर पर तेज़ होता है लेकिन, क्योंकि यह कंप्यूटर हार्डवेयर प्लेटफ़ॉर्म के लिए विशिष्ट है, यह पोर्टेबल नहीं है। एक आभासी मशीन के लिए निर्देश सेट उत्पन्न करने और प्रत्येक हार्डवेयर प्लेटफॉर्म पर दुभाषिया (कंप्यूटिंग) का उपयोग करने के लिए एक अलग दृष्टिकोण है। दुभाषिया वर्चुअल मशीन वातावरण को तुरंत चालू करता है और निर्देशों को निष्पादित करता है। इस प्रकार, केवल दुभाषिया को संकलित किया जाना चाहिए।
शुरुआती कंप्यूटरों में अपेक्षाकृत कम मेमोरी होती थी। उदाहरण के लिए, अधिकांश दिनांक जनरल नोवा, IBM 1130, और कई पहले माइक्रो कंप्यूटरों में केवल 4 kB RAM स्थापित थी। नतीजतन, उपलब्ध मेमोरी में फिट होने के लिए प्रोग्राम के आकार को कम करने के तरीके खोजने की कोशिश में बहुत समय व्यतीत हुआ।
एक समाधान एक दुभाषिया का उपयोग करना है जो एक समय में प्रतीकात्मक भाषा को थोड़ा पढ़ता है, और कार्यों को करने के लिए कार्यों को बुलाता है। चूंकि स्रोत कोड आमतौर पर परिणामी मशीन कोड की तुलना में अधिक कोड घनत्व होता है, यह समग्र मेमोरी उपयोग को कम कर सकता है। यही कारण था कि Microsoft BASIC एक दुभाषिया है:[lower-alpha 1] इसके अपने कोड को Altair 8800 जैसी मशीनों की 4 kB मेमोरी को उपयोगकर्ता के स्रोत कोड के साथ साझा करना था। एक कंपाइलर सोर्स लैंग्वेज से मशीन कोड में ट्रांसलेट होता है, इसलिए कंपाइलर, सोर्स और आउटपुट सभी एक ही समय में मेमोरी में होने चाहिए। एक दुभाषिया में, कोई आउटपुट नहीं होता है।
थ्रेडेड कोड संकलित कोड के लिए एक स्वरूपण शैली है जो स्मृति उपयोग को कम करता है। कार्यक्रम में प्रत्येक घटना पर एक ऑपरेशन के हर चरण को लिखने के बजाय, जैसा कि उदाहरण के लिए मैक्रो कोडांतरक में आम था, संकलक कोड के प्रत्येक सामान्य बिट को सबरूटीन में लिखता है। इस प्रकार, प्रत्येक बिट स्मृति में केवल एक ही स्थान पर मौजूद है (देखें स्वयं को दोहराएं नहीं)। इन कार्यक्रमों में शीर्ष-स्तरीय एप्लिकेशन में सबरूटीन कॉल के अलावा और कुछ नहीं हो सकता है। इन सबरूटीन्स में से कई, बदले में, निचले स्तर के सबरूटीन कॉल्स के अलावा और कुछ नहीं होते हैं।
मेनफ्रेम और कुछ शुरुआती माइक्रोप्रोसेसरों जैसे आरसीए 1802 को सबरूटीन कॉल करने के लिए कई निर्देशों की आवश्यकता होती है। शीर्ष-स्तरीय एप्लिकेशन में और कई सबरूटीन्स में, उस क्रम को लगातार दोहराया जाता है, जिसमें केवल सबरूटीन एड्रेस एक कॉल से दूसरे कॉल में बदलता रहता है। इसका मतलब यह है कि कई फ़ंक्शन कॉल वाले प्रोग्राम में काफी मात्रा में बार-बार कोड भी हो सकता है।
इसे संबोधित करने के लिए, थ्रेडेड कोड सिस्टम ने एक ऑपरेटर में फ़ंक्शन कॉल का प्रतिनिधित्व करने के लिए छद्म कोड का इस्तेमाल किया। रन टाइम पर, एक छोटा दुभाषिया शीर्ष-स्तरीय कोड को स्कैन करेगा, स्मृति में उपनेमका का पता निकालेगा, और इसे कॉल करेगा। अन्य प्रणालियों में, इसी मूल अवधारणा को शाखा तालिका, प्रेषण तालिका, या वर्चुअल विधि तालिका के रूप में कार्यान्वित किया जाता है, जिनमें से सभी में सबरूटीन पतों की एक तालिका होती है।
1970 के दशक के दौरान, हार्डवेयर डिजाइनरों ने सबरूटीन कॉल को तेज और सरल बनाने के लिए काफी प्रयास किया। बेहतर डिजाइनों पर, सबरूटीन को कॉल करने के लिए केवल एक ही निर्देश खर्च किया जाता है, इसलिए छद्म निर्देश का उपयोग कोई जगह नहीं बचाता है।[citation needed] इसके अतिरिक्त, इन कॉलों का प्रदर्शन अतिरिक्त ओवरहेड से लगभग मुक्त है। आज, हालांकि लगभग सभी प्रोग्रामिंग भाषाएं सबरूटीन्स में कोड को अलग करने पर ध्यान केंद्रित करती हैं, वे ऐसा कोड स्पष्टता और रखरखाव के लिए करते हैं, स्थान बचाने के लिए नहीं।
थ्रेडेड कोड सिस्टम फ़ंक्शन कॉल की उस सूची को बदलकर कमरे को बचाते हैं, जहां निष्पादन टोकन की सूची के साथ केवल सबरूटीन पता एक कॉल से दूसरे कॉल में बदलता है, जो अनिवार्य रूप से कॉल ऑपकोड (ओं) के साथ फ़ंक्शन कॉल होते हैं, पीछे छोड़ देते हैं केवल पतों की एक सूची।[3][4][5][6][7] इन वर्षों में, प्रोग्रामर ने उस दुभाषिया या छोटे चयनकर्ता पर कई बदलाव किए हैं। पतों की सूची में विशेष पता एक इंडेक्स, सामान्य प्रयोजन रजिस्टर या सूचक (कंप्यूटर प्रोग्रामिंग) का उपयोग करके निकाला जा सकता है। पते प्रत्यक्ष या अप्रत्यक्ष, सन्निहित या गैर-सन्निहित (पॉइंटर्स द्वारा जुड़े हुए), सापेक्ष या निरपेक्ष, संकलन समय पर हल या गतिशील रूप से निर्मित हो सकते हैं। सभी परिस्थितियों के लिए कोई भी भिन्नता सर्वोत्तम नहीं है।
विकास
जगह बचाने के लिए, प्रोग्रामर्स ने सबरूटीन कॉल्स की सूचियों को सबरूटीन पतों की सरल सूचियों में निचोड़ा, और बदले में प्रत्येक सबरूटीन को कॉल करने के लिए एक छोटे लूप का उपयोग किया। उदाहरण के लिए, निम्नलिखित स्यूडोकोड दो संख्याओं A और B को जोड़ने के लिए इस तकनीक का उपयोग करता है। उदाहरण में, सूची को थ्रेड लेबल किया गया है और एक चर ip (निर्देश सूचक) सूची के भीतर हमारे स्थान को ट्रैक करता है। एक अन्य चर एसपी (स्टैक पॉइंटर) में मेमोरी में कहीं और पता होता है जो अस्थायी रूप से मान रखने के लिए उपलब्ध होता है।
<वाक्यविन्यास प्रकाश लैंग = सी> शुरू करना:
ip = &thread // '&pushA' पते की ओर इशारा करता है, पाठ्य लेबल 'धागा' नहीं
ऊपर:
जंप *आईपी++ // थ्रेड में पता करने के लिए आईपी का पालन करें, सबरूटीन के लिए उस पते का पालन करें, अग्रिम आईपी
धागा:
&pushA &pushB &जोड़ना ...
पुशा:
*sp++ = A // उपलब्ध मेमोरी के लिए sp का अनुसरण करें, वहां A को स्टोर करें, आगे sp को आगे बढ़ाएं ऊपर कूदो
पुशबी:
*एसपी++ = बी ऊपर कूदो
जोड़ना:
addend1 = *--sp // स्टैक से शीर्ष मान पॉप करें addend2 = *--sp // स्टैक से दूसरा मान पॉप करें *sp++ = addend1 + addend2 // दोनों मानों को एक साथ जोड़ें और परिणाम को स्टैक के शीर्ष पर संग्रहीत करें ऊपर कूदो
</वाक्यविन्यास हाइलाइट>
कॉलिंग लूप at top
इतना सरल है कि इसे प्रत्येक उपनेमका के अंत में इनलाइन दोहराया जा सकता है। नियंत्रण अब एक बार कूदता है, एक उपनेमका के अंत से दूसरे की शुरुआत तक, दो बार कूदने के बजाय top
. उदाहरण के लिए:
<वाक्यविन्यास प्रकाश लैंग = सी> शुरू करना:
ip = &thread // ip &pushA को इंगित करता है (जो pushA के पहले निर्देश को इंगित करता है) jump *ip++ // pushA के पहले निर्देश पर नियंत्रण भेजें और ip को &pushB पर आगे बढ़ाएं
धागा:
&pushA &pushB &जोड़ना ...
पुशा:
*sp++ = A // उपलब्ध मेमोरी के लिए sp का अनुसरण करें, वहां A को स्टोर करें, आगे sp को आगे बढ़ाएं कूद * आईपी ++ // नियंत्रण भेजें जहां आईपी कहता है (यानी पुशबी के लिए) और अग्रिम आईपी
पुशबी:
*एसपी++ = बी कूदो * आईपी ++
जोड़ना:
addend1 = *--sp // स्टैक से शीर्ष मान पॉप करें addend2 = *--sp // स्टैक से दूसरा मान पॉप करें *sp++ = addend1 + addend2 // दोनों मानों को एक साथ जोड़ें और परिणाम को स्टैक के शीर्ष पर संग्रहीत करें कूदो * आईपी ++
</वाक्यविन्यास हाइलाइट>
इसे डायरेक्ट थ्रेडेड कोड (डीटीसी) कहा जाता है। हालांकि तकनीक पुरानी है, थ्रेडेड कोड शब्द का पहला व्यापक रूप से परिचालित उपयोग संभवतः जेम्स आर. बेल का 1973 का लेख थ्रेडेड कोड है।[8] 1970 में, चार्ल्स एच. मूर ने अपनी फोर्थ वर्चुअल मशीन के लिए एक अधिक कॉम्पैक्ट व्यवस्था, अप्रत्यक्ष थ्रेडेड कोड (ITC) का आविष्कार किया। मूर इस व्यवस्था पर इसलिए पहुंचे क्योंकि डेटा जनरल नोवा मिनीकंप्यूटर के प्रत्येक पते में एक अप्रत्यक्ष बिट था, जिसने आईटीसी को आसान और तेज़ बना दिया। बाद में, उन्होंने कहा कि उन्हें यह इतना सुविधाजनक लगा कि उन्होंने बाद के सभी फोर्थ डिजाइनों में इसका प्रचार किया।[9] आज, कुछ फोर्थ कंपाइलर्स प्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं जबकि अन्य अप्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं। निष्पादक किसी भी तरह से कार्य करते हैं।
थ्रेडिंग मॉडल
व्यावहारिक रूप से सभी निष्पादन योग्य थ्रेडेड कोड सबरूटीन्स (प्रत्येक विधि को थ्रेडिंग मॉडल कहा जाता है) को लागू करने के लिए इन विधियों में से एक या दूसरे का उपयोग करता है।
डायरेक्ट थ्रेडिंग
थ्रेड में पते मशीनी भाषा के पते होते हैं। यह फॉर्म सरल है, लेकिन इसमें ओवरहेड्स हो सकते हैं क्योंकि थ्रेड में केवल मशीन के पते होते हैं, इसलिए आगे के सभी मापदंडों को अप्रत्यक्ष रूप से मेमोरी से लोड किया जाना चाहिए। कुछ फोर्थ सिस्टम डायरेक्ट-थ्रेडेड कोड उत्पन्न करते हैं। कई मशीनों पर डायरेक्ट-थ्रेडिंग सबरूटीन थ्रेडिंग की तुलना में तेज़ होती है (नीचे संदर्भ देखें)।
स्टैक मशीन का एक उदाहरण अनुक्रम पुश ए, पुश बी, एड को निष्पादित कर सकता है। इसका अनुवाद निम्नलिखित थ्रेड और रूटीन में किया जा सकता है, जहाँ ip
लेबल किए गए पते पर प्रारंभ किया गया है thread
(यानी, पता जहां &pushA
रखा है)।
<वाक्यविन्यास प्रकाश लैंग = सी>
- define पुश(x) (*sp++ = (x))
- define POP() (*--sp)
शुरू करना:
ip = &thread // ip &pushA को इंगित करता है (जो pushA के पहले निर्देश को इंगित करता है) jump *ip++ // pushA के पहले निर्देश पर नियंत्रण भेजें और ip को &pushB पर आगे बढ़ाएं
धागा:
&pushA &pushB &जोड़ना ...
पुशा:
पुश (ए) कूद * आईपी ++ // नियंत्रण भेजें जहां आईपी कहता है (यानी पुशबी के लिए) और अग्रिम आईपी
पुशबी:
पुश (बी) कूदो * आईपी ++
जोड़ना:
परिणाम = पीओपी () + पीओपी () पुश (परिणाम) कूदो * आईपी ++
</वाक्यविन्यास हाइलाइट>
वैकल्पिक रूप से, ऑपरेंड को थ्रेड में शामिल किया जा सकता है। यह उपरोक्त आवश्यक कुछ संकेतों को हटा सकता है, लेकिन धागे को बड़ा बनाता है:
<वाक्यविन्यास प्रकाश लैंग = सी>
- define पुश(x) (*sp++ = (x))
- define POP() (*--sp)
शुरू करना:
आईपी \u003d और धागा कूदो * आईपी ++
धागा:
&धकेलना &ए // पता जहां ए संग्रहीत है, शाब्दिक ए नहीं &धकेलना &बी &जोड़ना ...
धकेलना:
variable_address = *ip++ // आईपी को पिछले ऑपरेंड पते पर ले जाना चाहिए, क्योंकि यह एक सबरूटीन पता नहीं है PUSH(*variable_address) // वेरिएबल से वैल्यू पढ़ें और स्टैक पर पुश करें कूदो * आईपी ++
जोड़ना:
परिणाम = पीओपी () + पीओपी () पुश (परिणाम) कूदो * आईपी ++
</वाक्यविन्यास हाइलाइट>
अप्रत्यक्ष थ्रेडिंग
अप्रत्यक्ष थ्रेडिंग पॉइंटर्स का उपयोग उन स्थानों पर करती है जो बदले में मशीन कोड को इंगित करते हैं। इनडायरेक्ट पॉइंटर को ऑपरेंड द्वारा फॉलो किया जा सकता है जो थ्रेड में बार-बार स्टोर करने के बजाय इनडायरेक्ट ब्लॉक में स्टोर किए जाते हैं। इस प्रकार, प्रत्यक्ष-थ्रेडेड कोड की तुलना में अप्रत्यक्ष कोड अक्सर अधिक कॉम्पैक्ट होता है। संकेत आम तौर पर इसे धीमा कर देता है, हालांकि आमतौर पर बाइटकोड दुभाषियों की तुलना में तेज़ होता है। जहां हैंडलर ऑपरेंड में मान और प्रकार दोनों शामिल होते हैं, डायरेक्ट-थ्रेडेड कोड पर स्थान की बचत महत्वपूर्ण हो सकती है। पुराने फोर्थ सिस्टम आमतौर पर अप्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं।
उदाहरण के लिए, यदि लक्ष्य पुश ए, पुश बी, ऐड निष्पादित करना है, तो निम्न का उपयोग किया जा सकता है। यहाँ, ip
पता करने के लिए प्रारंभ किया गया है &thread
, प्रत्येक कोड खंड (push
, add
) के माध्यम से डबल-इनडायरेक्टिंग द्वारा पाया जाता है ip
और एक अप्रत्यक्ष ब्लॉक; और फ़्रैगमेंट के किसी भी ऑपरेंड को फ़्रैगमेंट के पते के बाद अप्रत्यक्ष ब्लॉक में पाया जाता है। इसके लिए वर्तमान सबरूटीन को अंदर रखने की आवश्यकता है ip
, पिछले सभी उदाहरणों के विपरीत जहां इसमें अगले सबरूटीन को बुलाया जाना था।
<वाक्यविन्यास प्रकाश लैंग = सी> शुरू करना:
आईपी \u003d और धागा // 'और i_pushA' की ओर इशारा करता है जंप *(*आईपी) // 'पुश' के पहले निर्देश के लिए पॉइंटर्स का पालन करें, अभी तक आईपी को आगे न बढ़ाएं
धागा:
&i_pushA &i_pushB &मैं जोड़ना ...
i_pushA:
&धकेलना &ए
i_pushB:
&धकेलना &बी
मैं जोड़ना:
&जोड़ना
धकेलना:
*sp++ = *(*ip + 1) // ऑपरेंड एड्रेस के लिए अप्रत्यक्ष ब्लॉक के 1 अतीत की शुरुआत देखें जंप *(*++ip) // थ्रेड में अग्रिम आईपी, अगले अप्रत्यक्ष ब्लॉक के माध्यम से अगले सबरूटीन में कूदें
जोड़ना:
addend1 = *--sp addend2 = *--sp *एसपी++ = एडेंड1 + एडेंड2 कूदो *(*++आईपी)
</वाक्यविन्यास हाइलाइट>
सबरूटीन थ्रेडिंग
तथाकथित सबरूटीन-थ्रेडेड कोड (कॉल-थ्रेडेड कोड भी) में मशीन-भाषा कॉल निर्देशों की एक श्रृंखला होती है (या सीधे थ्रेडिंग के जंप के उपयोग के विपरीत, कॉल करने के लिए फ़ंक्शन के पते)। ALGOL, फोरट्रान, कोबोल और कुछ फोर्थ सिस्टम के शुरुआती कंपाइलर अक्सर सबरूटीन-थ्रेडेड कोड का उत्पादन करते थे। इनमें से कई प्रणालियों में कोड ऑपरेंड के लास्ट-इन-फर्स्ट-आउट (एलआईएफओ) स्टैक पर संचालित होता है, जिसके लिए कंपाइलर सिद्धांत अच्छी तरह से विकसित था। अधिकांश आधुनिक प्रोसेसर में सबरूटीन कॉल और रिटर्न निर्देशों के लिए विशेष हार्डवेयर समर्थन होता है, इसलिए प्रति प्रेषण एक अतिरिक्त मशीन निर्देश का ओवरहेड कुछ हद तक कम हो जाता है।
Gforth कंपाइलर के सह-निर्माता एंटोन एर्टल ने कहा कि लोकप्रिय मिथकों के विपरीत, सबरूटीन थ्रेडिंग आमतौर पर डायरेक्ट थ्रेडिंग की तुलना में धीमी होती है।[10] हालाँकि, Ertl के सबसे हालिया परीक्षण[1]दिखाएँ कि 25 में से 15 परीक्षण मामलों में सबरूटीन थ्रेडिंग सीधे थ्रेडिंग से तेज़ है। अधिक विशेष रूप से, उन्होंने पाया कि डायरेक्ट थ्रेडिंग एक्सॉन, ओपर्टन और एथलॉन प्रोसेसर पर सबसे तेज़ थ्रेडिंग मॉडल है, पेंटियम एम प्रोसेसर पर अप्रत्यक्ष थ्रेडिंग सबसे तेज़ है, और सबरूटीन थ्रेडिंग पेंटियम 4, पेंटियम III और पीपीसी प्रोसेसर पर सबसे तेज़ है।
पुश A के लिए कॉल थ्रेडिंग के उदाहरण के रूप में, B को पुश करें, जोड़ें:
<वाक्यविन्यास प्रकाश लैंग = सी> धागा:
कॉल pushA कॉल पुश बी कॉल जोड़ें गीला करना
पुशा:
*एसपी++ = ए गीला करना
पुशबी:
*एसपी++ = बी गीला करना
जोड़ना:
addend1 = *--sp addend2 = *--sp *एसपी++ = एडेंड1 + एडेंड2 गीला करना
</वाक्यविन्यास हाइलाइट>
टोकन थ्रेडिंग
टोकन-थ्रेडेड कोड संचालन की तालिका में सूचकांकों की सूची के रूप में थ्रेड को लागू करता है; घनत्व और दक्षता के लिए इंडेक्स चौड़ाई को स्वाभाविक रूप से जितना संभव हो उतना छोटा चुना जावा (प्रोग्रामिंग भाषा) में आसानी के लिए 1 बाइट / 8-बिट्स प्राकृतिक पसंद है, लेकिन 4-बिट्स जैसे छोटे आकार, या 12 या 16 बिट्स जैसे बड़े आकार का उपयोग समर्थित संचालन की संख्या के आधार पर किया जा सकता है। जब तक इंडेक्स की चौड़ाई को मशीन पॉइंटर की तुलना में संकरा चुना जाता है, तब तक यह प्रोग्रामर द्वारा विशेष प्रयास किए बिना स्वाभाविक रूप से अन्य थ्रेडिंग प्रकारों की तुलना में अधिक कॉम्पैक्ट होगा। यह आमतौर पर अन्य थ्रेडिंग के आकार का आधा से तीन-चौथाई होता है, जो स्वयं एक चौथाई से आठवें गैर-थ्रेडेड कोड के आकार का होता है। तालिका के संकेतक या तो अप्रत्यक्ष या प्रत्यक्ष हो सकते हैं। कुछ फोर्थ कंपाइलर्स टोकन-थ्रेडेड कोड उत्पन्न करते हैं। कुछ प्रोग्रामर पी-कोड मशीन | कुछ पास्कल (प्रोग्रामिंग भाषा) कंपाइलर्स द्वारा उत्पन्न पी-कोड, साथ ही साथ .NET Framework|.NET, Java (प्रोग्रामिंग लैंग्वेज), BASIC और कुछ C (प्रोग्रामिंग लैंग्वेज) द्वारा उपयोग किए जाने वाले बाईटकोड्स पर विचार करते हैं। संकलक, टोकन-थ्रेडिंग होना।
एक सामान्य दृष्टिकोण, ऐतिहासिक रूप से, बायटेकोड है, जो आमतौर पर स्टैक-आधारित वर्चुअल मशीन के साथ 8-बिट ऑपकोड का उपयोग करता है। मूलप्ररूपी बायटेकोड इंटरप्रेटर (कंप्यूटिंग) को डिकोड और डिस्पैच दुभाषिया के रूप में जाना जाता है और यह इस प्रकार है:
<वाक्यविन्यास प्रकाश लैंग = सी> शुरू करना:
वीपीसी = और थ्रेड
प्रेषण:
Addr = decode(&vpc) // अगले बायटेकोड ऑपरेशन को पॉइंटर से मशीन कोड में बदलें जो इसे लागू करता है // कोई भी इंटर-इंस्ट्रक्शन ऑपरेशंस यहां पर किए जाते हैं (जैसे ग्लोबल स्टेट अपडेट करना, इवेंट प्रोसेसिंग आदि) कूदो
CODE_PTR डिकोड (BYTE_CODE **p) {
// अधिक जटिल एन्कोडिंग में, चुनने या नियंत्रण/मोड फ़्लैग के बीच चुनने के लिए कई टेबल हो सकते हैं वापसी तालिका [* (* पी) ++];
} थ्रेड: / * में बायटेकोड होता है, न कि मशीन के पते। इसलिए यह अधिक सघन है। */
1 /*पुषा*/ 2 /*पुशबी*/ 0 /*जोड़ें*/
मेज:
&जोड़ें /* टेबल[0] = मशीन कोड का पता जो बाईटेकोड 0 लागू करता है */ और पुशा /* टेबल[1] ... */ और पुशबी /* तालिका [2] ... */
पुशा:
*एसपी++ = ए कूद प्रेषण
पुशबी:
*एसपी++ = बी कूद प्रेषण
जोड़ना:
addend1 = *--sp addend2 = *--sp *एसपी++ = एडेंड1 + एडेंड2 कूद प्रेषण
</वाक्यविन्यास हाइलाइट>
यदि वर्चुअल मशीन केवल बाइट-आकार के निर्देशों का उपयोग करती है, decode()
बस से लाया गया है thread
, लेकिन अक्सर आमतौर पर 1-बाइट निर्देशों का उपयोग किया जाता है और कुछ कम-सामान्य मल्टीबाइट निर्देश (जटिल निर्देश सेट कंप्यूटर देखें), जिस स्थिति में decode()
अधिक जटिल है। एकल बाइट ऑपकोड का डिकोडिंग बहुत ही सरलता से और कुशलता से एक शाखा तालिका द्वारा सीधे एक इंडेक्स के रूप में ऑपकोड का उपयोग करके किया जा सकता है।
निर्देशों के लिए जहां व्यक्तिगत संचालन सरल होते हैं, जैसे कि पुश और ऐड, क्या निष्पादित करना है, यह तय करने में शामिल कम्प्यूटेशनल ओवरहेड वास्तव में इसे निष्पादित करने की लागत से बड़ा है, इसलिए ऐसे दुभाषिए अक्सर मशीन कोड की तुलना में बहुत धीमे होते हैं। हालांकि, अधिक जटिल (यौगिक) निर्देशों के लिए, ओवरहेड प्रतिशत आनुपातिक रूप से कम महत्वपूर्ण है।
ऐसे समय होते हैं जब टोकन-थ्रेडेड कोड कभी-कभी समतुल्य मशीन कोड की तुलना में तेजी से चल सकता है जब वह मशीन कोड भौतिक CPU के L1 निर्देश कैश में फ़िट होने के लिए बहुत बड़ा हो जाता है। थ्रेडेड कोड का उच्च कोड घनत्व, विशेष रूप से टोकन-थ्रेडेड कोड, इसे L1 कैश में पूरी तरह से फिट होने की अनुमति दे सकता है, जब यह अन्यथा नहीं होता, जिससे कैश थ्रैशिंग से बचा जा सकता है। हालाँकि, थ्रेडेड कोड निर्देश कैश (प्रत्येक ऑपरेशन के कार्यान्वयन के लिए) के साथ-साथ डेटा कैश (बायटेकोड और टेबल के लिए) दोनों का उपभोग करता है, मशीन कोड के विपरीत जो केवल निर्देश कैश का उपभोग करता है; इसका मतलब है कि थ्रेडेड कोड किसी भी समय सीपीयू द्वारा प्रसंस्करण के लिए रखे जा सकने वाले डेटा की मात्रा के लिए बजट में खाएगा। किसी भी मामले में, यदि गणना की जा रही समस्या में डेटा की एक छोटी मात्रा में बड़ी संख्या में ऑपरेशन लागू करना शामिल है, तो थ्रेडेड कोड का उपयोग करना एक आदर्श अनुकूलन हो सकता है। [4]
हफ़मैन थ्रेडिंग
हफ़मैन थ्रेडेड कोड में हफ़मैन कोड के रूप में संग्रहीत टोकन की सूची होती है। एक हफ़मैन कोड बिट्स की एक चर-लंबाई वाली स्ट्रिंग है जो एक अद्वितीय टोकन की पहचान करती है। एक हफ़मैन-थ्रेडेड दुभाषिया इंडेक्स टेबल या पॉइंटर्स के एक पेड़ का उपयोग करके सबरूटीन्स का पता लगाता है जिसे हफ़मैन कोड द्वारा नेविगेट किया जा सकता है। हफमैन-थ्रेडेड कोड कंप्यूटर प्रोग्राम के लिए ज्ञात सबसे कॉम्पैक्ट प्रतिनिधित्वों में से एक है। कोड में प्रत्येक सबरूटीन को कॉल की आवृत्ति को मापकर इंडेक्स और कोड चुने जाते हैं। बार-बार कॉल करने के लिए सबसे छोटा कोड दिया जाता है। लगभग समान आवृत्तियों वाले संक्रियाओं को लगभग समान बिट-लंबाई वाले कोड दिए जाते हैं। अधिकांश हफ़मैन-थ्रेडेड सिस्टम को डायरेक्ट-थ्रेडेड फोर्थ सिस्टम के रूप में लागू किया गया है, और बड़ी मात्रा में धीमी गति से चलने वाले कोड को छोटे, सस्ते microcontroller में पैक करने के लिए उपयोग किया जाता है। सर्वाधिक प्रकाशित[11] उपयोग स्मार्ट कार्ड, खिलौने, कैलकुलेटर और घड़ियों में किया गया है। PBASIC में उपयोग किए जाने वाले बिट-ओरिएंटेड टोकन कोड को एक प्रकार के हफ़मैन-थ्रेडेड कोड के रूप में देखा जा सकता है।
कम उपयोग की जाने वाली थ्रेडिंग
एक उदाहरण स्ट्रिंग थ्रेडिंग है, जिसमें संचालन को स्ट्रिंग्स द्वारा पहचाना जाता है, आमतौर पर हैश टेबल द्वारा देखा जाता है। इसका उपयोग चार्ल्स एच. मूर के शुरुआती फोर्थ कार्यान्वयन और इलिनोइस विश्वविद्यालय में उरबाना-चैंपियन के प्रयोगात्मक हार्डवेयर-व्याख्या कंप्यूटर भाषा में किया गया था। इसका उपयोग बेशफर्थ में भी किया जाता है।
आरपीएल
Hewlett-Packard की RPL (प्रोग्रामिंग लैंग्वेज), जिसे पहली बार 1986 में HP-18C कैलकुलेटर में पेश किया गया था, एक प्रकार का मालिकाना हाइब्रिड डायरेक्ट-थ्रेडेड और इनडायरेक्ट-थ्रेडेड थ्रेडेड-इंटरप्रिटेड लैंग्वेज है, जो अन्य TILs के विपरीत, RPL ऑब्जेक्ट्स को एम्बेड करने की अनुमति देता है। रनस्ट्रीम यानी। पतों की धारा जिसके माध्यम से दुभाषिया सूचक आगे बढ़ता है। एक आरपीएल ऑब्जेक्ट को एक विशेष डेटा प्रकार के रूप में माना जा सकता है जिसकी इन-मेमोरी संरचना में ऑब्जेक्ट की शुरुआत में ऑब्जेक्ट प्रोलॉग का पता होता है, और उसके बाद डेटा या निष्पादन योग्य कोड होता है। ऑब्जेक्ट प्रोलॉग निर्धारित करता है कि ऑब्जेक्ट के शरीर को कैसे निष्पादित या संसाधित किया जाना चाहिए। आरपीएल इनर लूप का उपयोग करना,[12] जिसका आविष्कार और प्रकाशन किया गया था (और पेटेंट कराया गया था [13]) 1986 में विलियम सी. विकेस द्वारा और प्रोग्रामिंग एनवायरनमेंट, इंस्टीट्यूट फॉर एप्लाइड फोर्थ रिसर्च, इंक., 1988 में प्रकाशित, निष्पादन इस प्रकार है:
- IP (निर्देश सूचक) को हटा दें और इसे O (वर्तमान ऑब्जेक्ट पॉइंटर) में संग्रहीत करें
- आईपी को एक एड्रेस पॉइंटर की लंबाई से बढ़ाएं
- Dereference O और इसके पते को O_1 में संग्रहीत करें (यह संकेत का दूसरा स्तर है)
- पीसी (प्रोग्राम काउंटर) को O_1 प्लस एक एड्रेस पॉइंटर पर सेट करके अगले पॉइंटर या एम्बेडेड ऑब्जेक्ट पर नियंत्रण स्थानांतरित करें
- चरण 1 पर वापस जाएं
यह अधिक सटीक रूप से प्रतिनिधित्व कर सकता है:
<पूर्व>
ओ = [मैं] मैं = मैं + Δ पीसी = [ओ] + Δ
</पूर्व>
जहाँ ऊपर, O वर्तमान ऑब्जेक्ट पॉइंटर है, I इंटरप्रेटर पॉइंटर है, Δ एक एड्रेस शब्द की लंबाई है और [] ऑपरेटर dereference के लिए खड़ा है।
जब किसी ऑब्जेक्ट पॉइंटर या एम्बेडेड ऑब्जेक्ट पर नियंत्रण स्थानांतरित किया जाता है, तो निष्पादन निम्नानुसार जारी रहता है:
<पूर्व> PROLOG -> PROLOG (प्रोलॉग कोड की शुरुआत में प्रोलॉग पता खुद को इंगित करता है)
अगर ओ + Δ =/= पीसी फिर गोटो अप्रत्यक्ष (प्रत्यक्ष निष्पादन के लिए परीक्षण) ओ = आई - Δ (एम्बेडेड ऑब्जेक्ट की शुरुआत को इंगित करने के लिए सही ओ) I = I + α (एम्बेडेड ऑब्जेक्ट के बाद इंगित करने के लिए सही करें जहां α ऑब्जेक्ट की लंबाई है) अप्रत्यक्ष (बाकी प्रोलॉग)
</पूर्व>
एचपी के एचपी शनि माइक्रोप्रोसेसरों पर जो आरपीएल का उपयोग करते हैं, एक वास्तुशिल्प/प्रोग्रामिंग ट्रिक द्वारा संभव बनाया गया एक तीसरा स्तर है जो तेजी से निष्पादन की अनुमति देता है।[12]
शाखाएँ
सभी दुभाषियों में, एक शाखा केवल थ्रेड पॉइंटर (ip
) थ्रेड में किसी भिन्न पते पर। एक कंडीशनल जंप-इफ-जीरो ब्रांच जो केवल तभी जंप करती है जब टॉप-ऑफ-स्टैक वैल्यू शून्य हो, जैसा कि नीचे दिखाया गया है। यह उदाहरण डायरेक्ट थ्रेडिंग के एम्बेडेड पैरामीटर संस्करण का उपयोग करता है ताकि &thread[123]
लाइन वह गंतव्य है जहां स्थिति सही होने पर कूदना है, इसलिए इसे छोड़ दिया जाना चाहिए (ip++
) खत्म अगर शाखा नहीं ली जाती है।
<वाक्यविन्यास प्रकाश लैंग = सी> धागा:
... &brz & धागा [123] ...
ब्रज़:
when_true_ip = *ip++ // शाखा के लिए गंतव्य पता प्राप्त करें if (*--sp == 0) // स्टैक के शीर्ष पर पॉप/उपभोग करें और जांचें कि क्या यह शून्य है आईपी = जब_true_ip कूदो * आईपी ++
</वाक्यविन्यास हाइलाइट>
सामान्य सुविधाएं
एक मशीन में डेटा और रिटर्न स्टैक को अलग करने से स्टैक प्रबंधन कोड का एक बड़ा हिस्सा समाप्त हो जाता है, थ्रेडेड कोड के आकार को काफी हद तक कम कर देता है। डुअल-स्टैक सिद्धांत तीन बार स्वतंत्र रूप से उत्पन्न हुआ: बरोज़ लार्ज सिस्टम्स, फोर्थ (प्रोग्रामिंग लैंग्वेज) और परिशिष्ट भाग के लिए। इसका उपयोग कुछ जावा वर्चुअल मशीनों में किया जाता है।
थ्रेडेड वर्चुअल मशीन में अक्सर तीन प्रोसेसर रजिस्टर मौजूद होते हैं। सबरूटीन्स ('शब्द') के बीच डेटा पास करने के लिए एक और मौजूद है। ये:
- वर्चुअल मशीन का आईपी या आई (निर्देश सूचक) (वीएम को लागू करने वाले अंतर्निहित हार्डवेयर के कार्यक्रम गणक के साथ भ्रमित नहीं होना चाहिए)
- डब्ल्यू (कार्य सूचक)
- आरपी या आर (रिटर्न स्टैक (डेटा स्ट्रक्चर) पॉइंटर)
- एसपी या एस (शब्दों के बीच पैरामीटर पास करने के लिए पैरामीटर स्टैक पॉइंटर)
अक्सर, थ्रेडेड वर्चुअल मशीन, जैसे फोर्थ के कार्यान्वयन में, दिल में एक साधारण वर्चुअल मशीन होती है, जिसमें तीन आदिम होते हैं। वे हैं:
- घोंसला, जिसे डोकोल भी कहा जाता है
- unnest, या semi_s (;s)
- अगला
अप्रत्यक्ष-थ्रेडेड वर्चुअल मशीन में, यहाँ दिए गए ऑपरेशन हैं: <वाक्यविन्यास प्रकाश लैंग = सी>
अगला: * आईपी ++ -> डब्ल्यू कूदो ** डब्ल्यू ++ घोंसला: आईपी -> * आरपी ++ डब्ल्यू -> आईपी अगला अननेस्ट: *--आरपी -> आईपी अगला
</वाक्यविन्यास हाइलाइट>
यह भी देखें
- निरंतरता-गुजरने की शैली, जो ग्लोबल वेरिएबल को रिप्लेस करता है
ip
एक समारोह पैरामीटर के साथ - अभी-अभी संकलन
- वापसी-उन्मुख प्रोग्रामिंग: दूरस्थ कमजोर प्रणालियों का फायदा उठाने के लिए थ्रेडेड कोड की पुनर्खोज।
- पूंछ की पुनरावृत्ति
टिप्पणियाँ
- ↑ Dartmouth BASIC, upon which Microsoft BASIC is ultimately based, was a compiler that ran on mainframe machines.
संदर्भ
- ↑ 1.0 1.1 "Speed of various interpreter dispatch techniques V2".
- ↑ Dennis M. Ritchie, "The Development of the C Language", 1993. Quote: "The B compiler on the PDP-7 did not generate machine instructions, but instead 'threaded code' ..."
- ↑ David Frech. "muforth readme". section "Simple and tail-recursive native compiler".
- ↑ 4.0 4.1 Steve Heller. "Efficient C/C++ Programming: Smaller, Faster, Better". 2014. Chapter 5: "Do you need an interpreter?" p. 195.
- ↑ Jean-Paul Tremblay; P. G. Sorenson. "The Theory and Practice of Compiler Writing". 1985. p. 527
- ↑ "Wireless World: Electronics, Radio, Television, Volume 89". p. 73.
- ↑ "Byte, Volume 5". 1980. p. 212
- ↑ Bell, James R. (1973). "Threaded code". Communications of the ACM. 16 (6): 370–372. doi:10.1145/362248.362270.
- ↑ Moore, Charles H., published remarks in Byte Magazine's Forth Issue
- ↑ Ertl, Anton. "What is Threaded Code?".
- ↑ Latendresse, Mario; Feeley, Marc. Generation of Fast Interpreters for Huffman-Compressed Bytecode. Elsevier. CiteSeerX 10.1.1.156.2546.
- ↑ 12.0 12.1 Busby, Jonathan. "The RPL inner loop explained", "The Museum of HP Calculators", 7 September 2018, Retrieved on 27 December 2019
- ↑ Wickes, William C. (May 30, 1986). "Data processing system and method for the direct and indirect execution of uniformly structured object types". uspto.gov. Retrieved December 27, 2019.
बाहरी संबंध
- Anton Ertl's explanatory page What is Threaded Code? describes different threading techniques and provides further references.
- The Development of the C Language by Dennis M. Ritchie describes B (a precursor of C) as implemented using "threaded code".
- Thinking Forth Project includes the seminal (but out of print) book Thinking Forth by Leo Brodie published in 1984.
- Starting FORTH online version of the book Starting FORTH by Leo Brodie published in 1981.
- Brad Rodriguez's Moving FORTH: Part 1: Design Decisions in the Forth Kernel covers threading techniques in depth.
- History of general purpose CPUs
- GCC extensions. Labels as Values
- Horn, Joseph K. "What is RPL?". Archived from the original on 2017-09-17. Retrieved 2017-09-17. (NB. Brief overview on the threaded languages, System and User RPL, used on the HP calculators like the HP 48.)