थ्रेडेड कोड

From Vigyanwiki

मल्टी-थ्रेडेड प्रोग्रामिंग या जंप थ्रेडिंग से भ्रमित न हों।

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

थ्रेडेड कोड में वैकल्पिक पीढ़ी(जनरेशन) तकनीकों और वैकल्पिक कॉलिंग कन्वेंशन द्वारा उत्पन्न कोड की तुलना में अपेक्षाकृत अधिक कोड संघनता होती है। कैश (कंप्यूटिंग) संरचना में, यह निष्पादन (कंप्यूटिंग) कुछ मंद हो सकता है।[citation needed] हालाँकि, एक प्रोग्राम जो एक कंप्यूटर प्रोसेसर के सेंट्रल प्रोसेसिंग यूनिट कैश में संयोजित होने के लिए अपेक्षाकृत अधिक छोटा है, बड़े प्रोग्राम की तुलना में तीव्रता से चल सकता है जो कई कैश मिस का सामना करता है।[1] थ्रेड स्विचिंग पर छोटे प्रोग्राम भी तीव्र हो सकते हैं, जब अन्य प्रोग्राम कैश पूरित हो चुके हों।

थ्रेडेड कोड को प्रोग्रामिंग भाषा के कई कंपाइलरों में इसके उपयोग के लिए जाना जाता है, जैसे फोर्थ (प्रोग्रामिंग भाषा), प्रारम्भिक सर्व-उद्देश्यीय प्रतीकात्मक निर्देश कोड के कई कार्यान्वयन, सामान्य व्यवसाय उन्मुखी भाषा के कुछ कार्यान्वयन, B के प्रारम्भिक संस्करण (प्रोग्रामिंग भाषा),[2] और छोटे मिनी कंप्यूटर और एमेच्योर रेडियो उपग्रह के लिए अन्य भाषाएं सम्मिलित है।[citation needed]


इतिहास

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

प्रारम्भिक कंप्यूटरों में अपेक्षाकृत कम मेमोरी होती थी। उदाहरण के लिए, अधिकांश डेटा जनरल नोवा,अंतर्राष्ट्रीय व्यापार मशीन 1130, और कई पहले माइक्रो कंप्यूटरों में केवल 4 किलोबाइट रैंडम एक्सेस मेमोरी स्थापित थी। परिणामस्वरूप, उपलब्ध मेमोरी में संयोजित होने के लिए प्रोग्राम के आकार को कम करने के तरीके खोजने के प्रयास में अधिक समय व्यतीत हुआ।

एक समाधान एक दुभाषिया का उपयोग करना है जो एक समय में प्रतीकात्मक भाषा को अल्प पढ़ता है, और कार्य करने के लिए फ़ंक्शन को कॉल करता है। चूंकि स्रोत कोड सामान्य रूप से परिणामी मशीन कोड की तुलना में अधिक कोड घनत्व होता है, यह समग्र मेमोरी उपयोग को कम कर सकता है। यही कारण था कि माइक्रोसॉफ्ट प्रारम्भिक सर्व-उद्देश्यीय प्रतीकात्मक निर्देश कोड एक दुभाषिया है:[lower-alpha 1] इसके अपने कोड को अल्टेयर 8800 जैसी मशीनों की 4 किलोबाइट मेमोरी को उपयोगकर्ता के स्रोत कोड के साथ साझा करना था। एक कंपाइलर स्त्रोत भाषा से मशीन कोड में अनुवाद होता है, इसलिए कंपाइलर, सोर्स और आउटपुट सभी एक ही समय में मेमोरी में होने चाहिए। एक दुभाषिया में, कोई आउटपुट नहीं होता है।

थ्रेडेड कोड संकलित कोड के लिए एक स्वरूपण शैली है जो स्मृति उपयोग को कम करता है। प्रोग्राम में प्रत्येक उपस्थिति पर एक संचालन के प्रत्येक चरण को लिखने के अतिरिक्त, जैसा कि उदाहरण के लिए मैक्रो कोडांतरक में आम था, संकलक कोड के प्रत्येक सामान्य बिट को सबरूटीन में लिखता है। इस प्रकार, प्रत्येक बिट स्मृति में केवल एक ही स्थान पर सम्मिलित है (देखें स्वयं को दोहराएं नहीं)। इन प्रोग्रामो में शीर्ष-स्तरीय एप्लिकेशन में सबरूटीन कॉल के अतिरिक्त और कुछ नहीं हो सकता है। इन सबरूटीन्स में से कई, बदले में, निचले स्तर के सबरूटीन कॉल्स के अतिरिक्त और कुछ नहीं होते हैं।

मेनफ्रेम और कुछ प्रारम्भिक माइक्रोप्रोसेसरों जैसे आरसीए 1802 को सबरूटीन कॉल करने के लिए कई निर्देशों की आवश्यकता होती है। शीर्ष-स्तरीय एप्लिकेशन में और कई सबरूटीन्स में, उस क्रम को निरंतर पुनरावृत जाता है, जिसमें केवल सबरूटीन एड्रेस एक कॉल से दूसरे कॉल में परिवर्तित करता रहता है। इसका तात्पर्य यह है कि कई फ़ंक्शन कॉल वाले प्रोग्राम में अपेक्षाकृत अधिक मात्रा में बार-बार कोड भी हो सकता है।

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

1970 के दशक के समय, हार्डवेयर डिजाइनरों ने सबरूटीन कॉल को तीव्र और सामान्य बनाने के लिए अपेक्षाकृत अधिक प्रयास किया। अपेक्षाकृत अधिक डिजाइनों पर, सबरूटीन को कॉल करने के लिए केवल एक ही निर्देश व्यय किया जाता है, इसलिए स्यूडो निर्देश का उपयोग कोई स्थान नहीं बचाता है।[citation needed] इसके अतिरिक्त, इन कॉलों का प्रदर्शन अतिरिक्त ओवरहेड से लगभग मुक्त है। आज, हालांकि लगभग सभी प्रोग्रामिंग भाषाएं सबरूटीन्स में कोड को अलग करने पर ध्यान केंद्रित करती हैं, वे ऐसा कोड स्पष्टता और संरक्षण के लिए करते हैं, स्थान बचाने के लिए नहीं ऐसा नहीं करती है।

थ्रेडेड कोड सिस्टम फ़ंक्शन कॉल की उस सूची को परिवर्तित करके स्थान को बचाते हैं, जहां निष्पादन टोकन की सूची के साथ केवल सबरूटीन एड्रैस एक कॉल से दूसरे कॉल में बदलता है, जो अनिवार्य रूप से कॉल ऑपकोड (ओं) के साथ फ़ंक्शन कॉल होते हैं, केवल एक एड्रैस सूची को पीछे छोड़ देता है।[3][4][5][6][7]

इन वर्षों में, प्रोग्रामर ने उस दुभाषिया या छोटे चयनकर्ता पर कई परिवर्तन किए हैं। एड्रैस की सूची में विशेष एड्रैस एक इंडेक्स, सामान्य प्रयोजन रजिस्टर या पॉइंटर (कंप्यूटर प्रोग्रामिंग) का उपयोग करके निकाला जा सकता है। एड्रैस प्रत्यक्ष या अप्रत्यक्ष, सन्निहित या गैर-सन्निहित (पॉइंटर्स द्वारा जुड़े हुए), सापेक्ष या निरपेक्ष, संकलन समय पर संशोधित या गतिशील रूप से निर्मित हो सकते हैं। सभी परिस्थितियों के लिए कोई भी भिन्नता सर्वोत्तम नहीं है।

विकास

स्थान बचाने के लिए, प्रोग्रामर्स ने सबरूटीन कॉल्स की सूचियों को सबरूटीन एड्रैस की सामान्य सूचियों में निष्पीडित, और बदले में प्रत्येक सबरूटीन को कॉल करने के लिए एक छोटे लूप का उपयोग किया। उदाहरण के लिए, निम्नलिखित स्यूडोकोड दो संख्याओं A और B को जोड़ने के लिए इस तकनीक का उपयोग करता है। उदाहरण में, सूची को थ्रेड लेबल किया गया है और एक वेरिएबल आईपी (निर्देश पॉइंटर) सूची के अंदर हमारे स्थान को ट्रैक करता है। एक अन्य वेरिएबल एसपी (स्टैक पॉइंटर) में मेमोरी में कहीं और एड्रैस होता है जो अस्थायी रूप से मान रखने के लिए उपलब्ध होता है।

start:
 ip = &thread // points to the address '&pushA', not the textual label 'thread'
top:
 jump *ip++ // follow ip to address in thread, follow that address to subroutine, advance ip
thread:
 &pushA
 &pushB
 &add
 ...
pushA:
 *sp++ = A // follow sp to available memory, store A there, advance sp to next 
 jump top
pushB:
 *sp++ = B
 jump top
add:
 addend1 = *--sp // Pop the top value off the stack
 addend2 = *--sp // Pop second value off the stack
 *sp++ = addend1 + addend2 // Add the two values together and store the result on the top of the stack
 jump top

top पर कॉलिंग लूप इतना सामान्य है कि इसे प्रत्येक सबरूटीन के अंत में इनलाइन द्वारा पुनरावृत किया जा सकता है। topसे होकर दो बार जंप के अतिरिक्त नियंत्रण सिर्फ एक सबरूटीन के अंत से दूसरे के प्रारंभ तक एक बार जंप है। उदाहरण के लिए:

start:
 ip = &thread // ip points to &pushA (which points to the first instruction of pushA)
 jump *ip++ // send control to first instruction of pushA and advance ip to &pushB
thread:
 &pushA
 &pushB
 &add
 ...
pushA:
 *sp++ = A // follow sp to available memory, store A there, advance sp to next 
 jump *ip++ // send control where ip says to (i.e. to pushB) and advance ip
pushB:
 *sp++ = B
 jump *ip++
add:
 addend1 = *--sp // Pop the top value off the stack
 addend2 = *--sp // Pop second value off the stack
 *sp++ = addend1 + addend2 // Add the two values together and store the result on top of the stack
 jump *ip++

इसे प्रत्यक्ष थ्रेडेड कोड (डीटीसी) कहा जाता है। हालांकि तकनीक पुरानी है, थ्रेडेड कोड शब्द का पहला व्यापक रूप से परिचालित उपयोग संभवतः जेम्स आर. बेल का 1973 का लेख थ्रेडेड कोड है।[8]

1970 में, चार्ल्स एच. मूर ने अपनी फोर्थ वर्चुअल मशीन के लिए एक अधिक कॉम्पैक्ट व्यवस्था, अप्रत्यक्ष थ्रेडेड कोड (आईटीसी) का आविष्कार किया। मूर इस व्यवस्था पर इसलिए पहुंचे क्योंकि डेटा जनरल नोवा मिनीकंप्यूटर के प्रत्येक एड्रैस में एक अप्रत्यक्ष बिट था, जिसने आईटीसी को आसान और तीव्र बना दिया। बाद में, उन्होंने कहा कि उन्हें यह इतना सुविधाजनक लगा कि उन्होंने बाद के सभी फोर्थ डिजाइनों में इसका प्रचार किया।[9]

आज, कुछ फोर्थ कंपाइलर्स प्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं जबकि अन्य अप्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं। निष्पादक किसी भी तरह से कार्य करते हैं।

थ्रेडिंग मॉडल

व्यावहारिक रूप से सभी निष्पादन योग्य थ्रेडेड कोड सबरूटीन्स (प्रत्येक विधि को थ्रेडिंग मॉडल कहा जाता है) को प्रयुक्त करने के लिए इन विधियों में से एक या दूसरे का उपयोग करता है।

डायरेक्ट (प्रत्यक्ष) थ्रेडिंग

थ्रेड में एड्रैस मशीनी भाषा के एड्रैस होते हैं। यह प्रारूप सामान्य है, लेकिन इसमें ओवरहेड्स हो सकते हैं क्योंकि थ्रेड में केवल मशीन के एड्रैस होते हैं, इसलिए आगे के सभी मापदंडों को अप्रत्यक्ष रूप से मेमोरी से लोड किया जाना चाहिए। कुछ फोर्थ सिस्टम प्रत्यक्ष-थ्रेडेड कोड उत्पन्न करते हैं। कई मशीनों पर प्रत्यक्ष-थ्रेडिंग सबरूटीन थ्रेडिंग की तुलना में तीव्र होती है (नीचे संदर्भ देखें)।

स्टैक मशीन का एक उदाहरण "पुश A, पुश B, ऐड" अनुक्रम को निष्पादित कर सकता है। इसे निम्नलिखित थ्रेड और रूटीन में अनुवादित किया जा सकता है, जहां ip को लेबल किए गए thread (अर्थात, एड्रैस जहां &pushA संग्रहीत है) के एड्रैस पर प्रारंभ किया गया है।

#define PUSH(x) (*sp++ = (x))
#define POP() (*--sp)
start:
 ip = &thread // ip points to &pushA (which points to the first instruction of pushA)
 jump *ip++ // send control to first instruction of pushA and advance ip to &pushB
thread:
 &pushA
 &pushB
 &add
 ...
pushA:
 PUSH(A)
 jump *ip++ // send control where ip says to (i.e. to pushB) and advance ip
pushB:
 PUSH(B)
 jump *ip++
add:
 result = POP() + POP()
 PUSH(result)
 jump *ip++

वैकल्पिक रूप से, ऑपरेंड को थ्रेड में सम्मिलित किया जा सकता है। यह उपरोक्त आवश्यक कुछ संकेतों को हटा सकता है, लेकिन थ्रेड को बड़ा बनाता है:

#define PUSH(x) (*sp++ = (x))
#define POP() (*--sp)
start:
 ip = &thread
 jump *ip++
thread:
 &push
 &A // address where A is stored, not literal A
 &push
 &B
 &add
 ...
push:
 variable_address = *ip++ // must move ip past operand address, since it is not a subroutine address
 PUSH(*variable_address) // Read value from variable and push on stack
 jump *ip++
add:
 result = POP() + POP()
 PUSH(result)
 jump *ip++

इनडायरेक्ट (अप्रत्यक्ष) थ्रेडिंग

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

उदाहरण के लिए, यदि लक्ष्य पुश A, पुश B, ऐड निष्पादित करना है, तो निम्न का उपयोग किया जा सकता है। यहाँ, ip को &thread, को संबोधित करने के लिए प्रारंभ किया गया है, प्रत्येक कोड भाग (push, add) ip और एक अप्रत्यक्ष ब्लॉक के माध्यम से डबल-इनडायरेक्टिंग द्वारा पाया जाता है; और फ़्रैगमेंट के किसी भी ऑपरेंड को फ़्रैगमेंट के एड्रैस के बाद अप्रत्यक्ष ब्लॉक में पाया जाता है। इसके लिए वर्तमान सबरूटीन को ip, में रखने की आवश्यकता है, पिछले सभी उदाहरणों के विपरीत जहां इसमें अगले सबरूटीन को बुलाया जाना है।

start:
 ip = &thread // points to '&i_pushA'
 jump *(*ip) // follow pointers to 1st instruction of 'push', DO NOT advance ip yet
thread:
 &i_pushA
 &i_pushB
 &i_add
 ...
i_pushA:
 &push
 &A
i_pushB:
 &push
 &B
i_add:
 &add
push:
 *sp++ = *(*ip + 1) // look 1 past start of indirect block for operand address
 jump *(*++ip) // advance ip in thread, jump through next indirect block to next subroutine
add:
 addend1 = *--sp
 addend2 = *--sp
 *sp++ = addend1 + addend2
 jump *(*++ip)

सबरूटीन थ्रेडिंग

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

गफर्थ कंपाइलर के सह-निर्माता एंटोन एर्टल ने कहा कि लोकप्रिय मिथकों के विपरीत, सबरूटीन थ्रेडिंग सामान्य रूप से प्रत्यक्ष थ्रेडिंग की तुलना में मंद होती है।[10] हालाँकि, एर्टल के सबसे हाल के परीक्षण[1] दिखाते कि 25 में से 15 परीक्षण स्थितियों में सबरूटीन थ्रेडिंग प्रत्यक्ष थ्रेडिंग से तीव्र है। अधिक विशेष रूप से, उन्होंने पाया कि प्रत्यक्ष थ्रेडिंग एक्सॉन, ओपर्टन और एथलॉन प्रोसेसर पर सबसे तीव्र थ्रेडिंग मॉडल है, पेंटियम एम प्रोसेसर पर अप्रत्यक्ष थ्रेडिंग सबसे तीव्र है, और सबरूटीन थ्रेडिंग पेंटियम 4, पेंटियम III और पीपीसी प्रोसेसर पर सबसे तीव्र है।

"पुश A पुश B, ऐड" के लिए कॉल थ्रेडिंग के उदाहरण के रूप में:

thread:
 call pushA
 call pushB
 call add
 ret
pushA:
 *sp++ = A
 ret
pushB:
 *sp++ = B
 ret
add:
 addend1 = *--sp
 addend2 = *--sp
 *sp++ = addend1 + addend2
 ret

टोकन थ्रेडिंग

टोकन-थ्रेडेड कोड संचालन की तालिका में पॉइंटर की सूची के रूप में थ्रेड को प्रयुक्त करता है; घनत्व और दक्षता के लिए इंडेक्स चौड़ाई को स्वाभाविक रूप से जितना संभव हो उतना छोटा चयन जावा (प्रोग्रामिंग भाषा) में आसानी के लिए 1 बाइट / 8-बिट्स प्राकृतिक चयन है, लेकिन 4-बिट्स जैसे छोटे आकार, या 12 या 16 बिट्स जैसे बड़े आकार का उपयोग समर्थित संचालन की संख्या के आधार पर किया जा सकता है। जब तक इंडेक्स की चौड़ाई को मशीन पॉइंटर की तुलना में संकुचित चयन किया जाता है, तब तक यह प्रोग्रामर द्वारा विशेष प्रयास किए बिना स्वाभाविक रूप से अन्य थ्रेडिंग प्रकारों की तुलना में अधिक कॉम्पैक्ट होगा। यह सामान्य रूप से अन्य थ्रेडिंग के आकार का आधा से तीन-चौथाई होता है, जो स्वयं एक चौथाई से आठवें गैर-थ्रेडेड कोड के आकार का होता है। सारणी के संकेतक या तो अप्रत्यक्ष या प्रत्यक्ष हो सकते हैं। कुछ फोर्थ कंपाइलर्स टोकन-थ्रेडेड कोड उत्पन्न करते हैं। कुछ प्रोग्रामर टोकन-थ्रेडिंग होने के लिए कुछ पास्कल कंपाइलर्स द्वारा उत्पन्न "पी-कोड", साथ ही .नेट, जावा, प्रारंभ का सर्व-उद्देश्यीय प्रतीकात्मक निर्देश कोड और कुछ C कंपाइलर्स द्वारा उपयोग किए जाने वाले बाइटकोड्स पर विचार करते हैं।

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

start:
 vpc = &thread
dispatch:
 addr = decode(&vpc) // Convert the next bytecode operation to a pointer to machine code that implements it
 // Any inter-instruction operations are performed here (e.g. updating global state, event processing, etc)
 jump addr
CODE_PTR decode(BYTE_CODE **p) {
 // In a more complex encoding, there may be multiple tables to choose between or control/mode flags
 return table[*(*p)++];
}
thread: /* Contains bytecode, not machine addresses. Hence it is more compact. */
 1 /*pushA*/
 2 /*pushB*/
 0 /*add*/
table:
 &add /* table[0] = address of machine code that implements bytecode 0 */
 &pushA /* table[1] ... */
 &pushB /* table[2] ... */
pushA:
 *sp++ = A
 jump dispatch
pushB:
 *sp++ = B
 jump dispatch
add:
 addend1 = *--sp
 addend2 = *--sp
 *sp++ = addend1 + addend2
 jump dispatch

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

निर्देशों के लिए जहां व्यक्तिगत संचालन सामान्य होते हैं, जैसे कि पुश और ऐड, क्या निष्पादित करना है, यह निर्धारित करने में सम्मिलित कम्प्यूटेशनल ओवरहेड वास्तव में इसे निष्पादित करने की कीमत से बड़ा है, इसलिए ऐसे दुभाषिए प्रायः मशीन कोड की तुलना में बहुत मंद होते हैं। हालांकि, अधिक जटिल (यौगिक) निर्देशों के लिए, ओवरहेड प्रतिशत आनुपातिक रूप से कम महत्वपूर्ण है।

ऐसे समय होते हैं जब टोकन-थ्रेडेड कोड कभी-कभी समतुल्य मशीन कोड की तुलना में तीव्रता से चल सकता है जब वह मशीन कोड भौतिक सेंट्रल प्रोसेसिंग यूनिट के L1 निर्देश कैश में संयोजित होने के लिए बहुत बड़ा हो जाता है। थ्रेडेड कोड का उच्च कोड घनत्व, विशेष रूप से टोकन-थ्रेडेड कोड, इसे L1 कैश में पूरी तरह से संयोजित होने की स्वीकृति दे सकता है, जब यह अन्यथा नहीं होता, जिससे कैश थ्रैशिंग से बचा जा सकता है। हालाँकि, थ्रेडेड कोड निर्देश कैश (प्रत्येक संचालन के कार्यान्वयन के लिए) के साथ-साथ डेटा कैश (बायटेकोड और टेबल के लिए) दोनों का उपभोग करता है, मशीन कोड के विपरीत जो केवल निर्देश कैश का उपभोग करता है; इसका तात्पर्य है कि थ्रेडेड कोड किसी भी समय सेंट्रल प्रोसेसिंग यूनिट द्वारा प्रसंस्करण के लिए रखे जा सकने वाले डेटा की मात्रा के लिए बजट में व्यय होगा। किसी भी स्थिति में, यदि गणना की जा रही समस्या में डेटा की एक छोटी मात्रा में बड़ी संख्या में संचालन प्रयुक्त करना सम्मिलित है, तो थ्रेडेड कोड का उपयोग करना एक आदर्श अनुकूलन हो सकता है।[4]


हफ़मैन थ्रेडिंग

हफ़मैन थ्रेडेड कोड में हफ़मैन कोड के रूप में संग्रहीत टोकन की सूची होती है। एक हफ़मैन कोड बिट्स की एक वेरिएबल-लंबाई वाली स्ट्रिंग (शृंखला) है जो एक अद्वितीय टोकन की पहचान करती है। एक हफ़मैन-थ्रेडेड दुभाषिया इंडेक्स टेबल या पॉइंटर्स के एक ट्री का उपयोग करके सबरूटीन्स का पता लगाता है जिसे हफ़मैन कोड द्वारा नेविगेट किया जा सकता है। हफमैन-थ्रेडेड कोड कंप्यूटर प्रोग्राम के लिए ज्ञात सबसे कॉम्पैक्ट प्रतिनिधित्वों में से एक है। कोड में प्रत्येक सबरूटीन को कॉल की आवृत्ति को मापकर इंडेक्स और कोड चयन किए जाते हैं। बार-बार कॉल करने के लिए सबसे छोटा कोड दिया जाता है। लगभग समान आवृत्तियों वाले संक्रियाओं को लगभग समान बिट-लंबाई वाले कोड दिए जाते हैं। अधिकांश हफ़मैन-थ्रेडेड सिस्टम को प्रत्यक्ष-थ्रेडेड फोर्थ सिस्टम के रूप में प्रयुक्त किया गया है, और बड़ी मात्रा में मंद गति से चलने वाले कोड को छोटे, सस्ते माइक्रोकंट्रोलर्स में पैक करने के लिए उपयोग किया जाता है। सर्वाधिक प्रकाशित[11] उपयोग स्मार्ट कार्ड, खिलौने, कैलकुलेटर और घड़ियों में किया गया है। पीबीएसआईसी में उपयोग किए जाने वाले बिट-ओरिएंटेड टोकन कोड को एक प्रकार के हफ़मैन-थ्रेडेड कोड के रूप में देखा जा सकता है।

लैसर- थ्रेडिंग उपयोग

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

आरपीएल

हेवलेट पैकर्ड की पूर्व शिक्षण की मान्यता (प्रोग्रामिंग भाषा), जिसे पहली बार 1986 में हेवलेट पैकर्ड-18सी कैलकुलेटर(गणना-यंत्र) में प्रस्तुत किया गया था, एक प्रकार की अधिकारित हाइब्रिड प्रत्यक्ष-थ्रेडेड और इनडायरेक्ट-थ्रेडेड थ्रेडेड-इंटरप्रिटेड भाषा है, जो अन्य टीआईएल के विपरीत, पूर्व शिक्षण की मान्यता ऑब्जेक्ट्स" को "रनस्ट्रीम" में एम्बेड करने की स्वीकृति देता है।। एड्रैस के संचालन जिसके माध्यम से दुभाषिया पॉइंटर आगे बढ़ता है। एक आरपीएल ऑब्जेक्ट को एक विशेष डेटा प्रकार के रूप में माना जा सकता है जिसकी इन-मेमोरी संरचना में ऑब्जेक्ट की प्रारंभ में ऑब्जेक्ट प्रोलॉग का पता होता है, और उसके बाद डेटा या निष्पादन योग्य कोड होता है। ऑब्जेक्ट प्रोलॉग निर्धारित करता है कि ऑब्जेक्ट के भाग को कैसे निष्पादित या संसाधित किया जाना चाहिए। आरपीएल इनर लूप का उपयोग करते हुए,[12] जिसका आविष्कार और प्रकाशन किया गया था (और पेटेंट कराया गया था) [13] 1986 में विलियम सी विकेस द्वारा और और "प्रोग्रामिंग एनवायरनमेंट", इंस्टीट्यूट फॉर एप्लाइड फोर्थ रिसर्च, इंक, 1988 में प्रकाशित किया गया था। इस प्रकार है:

  1. आईपी (निर्देश पॉइंटर) को हटा दें और इसे ऑब्जेक्ट (वर्तमान ऑब्जेक्ट पॉइंटर) में संग्रहीत करें
  2. आईपी को एक एड्रेस पॉइंटर की लंबाई से बढ़ाएं
  3. भिन्नता ऑब्जेक्ट और इसके एड्रैस को ऑब्जेक्ट_1 में संग्रहीत करें (यह संकेत का दूसरा स्तर है)
  4. पीसी (प्रोग्राम काउंटर) को ऑब्जेक्ट_1 प्लस एक एड्रेस पॉइंटर पर सेट करके अगले पॉइंटर या एम्बेडेड ऑब्जेक्ट पर नियंत्रण स्थानांतरित करें
  5. चरण 1 पर वापस जाएं

यह अधिक परिशुद्ध रूप से प्रतिनिधित्व कर सकता है:

 O = [I]
 I = I + Δ
 PC = [O] + Δ

जहाँ ऊपर, ऑब्जेक्ट वर्तमान ऑब्जेक्ट पॉइंटर है, I इंटरप्रेटर पॉइंटर है, Δ एक एड्रेस शब्द की लंबाई है और '[]' ऑपरेटर "डीरेफरेंस" के लिए है।

जब किसी ऑब्जेक्ट पॉइंटर या एम्बेडेड ऑब्जेक्ट पर नियंत्रण स्थानांतरित किया जाता है, तो निष्पादन निम्नानुसार निरंतर रहता है:

 PROLOG -> PROLOG ( The prolog address at the start of the prolog code points to itself )
 IF O + Δ =/= PC
 THEN GOTO INDIRECT ( Test for direct execution )
        O = I - Δ ( Correct O to point to start of embedded object )
        I = I + α ( Correct I to point after embedded object where α is the length of the object )
 INDIRECT ( rest of prolog )

हेवलेट पैकर्ड के सैटर्न माइक्रोप्रोसेसरों पर जो आरपीएल का उपयोग करते हैं, एक संरचना/प्रोग्रामिंग ट्रिक द्वारा संभव बनाया गया एक तीसरा स्तर है जो तीव्रता से निष्पादन की स्वीकृति देता है।[12]


ब्रांच

सभी दुभाषियों में, एक ब्रांच केवल थ्रेड पॉइंटर (ip) थ्रेड में किसी भिन्न एड्रैस पर एक कंडीशनल जंप-इफ-जीरो ब्रांच जो केवल तभी जंप करती है जब टॉप-ऑफ-स्टैक वैल्यू शून्य हो, जैसा कि नीचे दिखाया गया है। यह उदाहरण प्रत्यक्ष थ्रेडिंग के एम्बेडेड पैरामीटर संस्करण का उपयोग करता है ताकि &thread[123] लाइन वह स्थान है जहां स्थिति सही होने पर जंप है, इसलिए इसे छोड़ दिया जाना चाहिए (ip++) इसीलिए ब्रांच नहीं ली जाती है।

thread:
 ...
 &brz
 &thread[123]
 ...
brz:
 when_true_ip = *ip++ // Get destination address for branch
 if (*--sp == 0)      // Pop/Consume top of stack and check if it's zero
 ip = when_true_ip
 jump *ip++

सामान्य सुविधाएं

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

थ्रेडेड वर्चुअल मशीन में प्रायः तीन प्रोसेसर रजिस्टर सम्मिलित होते हैं। सबरूटीन्स ('शब्द') के बीच डेटा पास करने के लिए एक अन्य सम्मिलित है। ये:

  • वर्चुअल मशीन का आईपी या आई (निर्देश पॉइंटर) (वीएम को प्रयुक्त करने वाले अंतर्निहित हार्डवेयर के प्रोग्राम गणक के साथ भ्रमित नहीं होना चाहिए)
  • डब्ल्यू (कार्य पॉइंटर)
  • आरपी या आर (प्रतिकृति स्टैक (डेटा स्ट्रक्चर) पॉइंटर)
  • एसपी या एस (शब्दों के बीच पैरामीटर पास करने के लिए पैरामीटर स्टैक पॉइंटर)

प्रायः, थ्रेडेड वर्चुअल मशीन, जैसे फोर्थ के कार्यान्वयन में, केंद्र में एक साधारण वर्चुअल मशीन होती है, जिसमें तीन प्रिमिटिव होते हैं। वे

  1. नेस्ट,जिसे डोकोल भी कहा जाता है
  2. अननेस्ट, या सेमी_एस (;एस)
  3. अगला

अप्रत्यक्ष-थ्रेडेड वर्चुअल मशीन में, यहाँ दिए गए संचालन हैं:

 next:
 *ip++ -> w
 jump **w++
 nest:
 ip -> *rp++
 w -> ip
 next
 unnest:
 *--rp -> ip
 next

यह भी देखें

टिप्पणियाँ

  1. Dartmouth BASIC, upon which Microsoft BASIC is ultimately based, was a compiler that ran on mainframe machines.


संदर्भ

  1. 1.0 1.1 "Speed of various interpreter dispatch techniques V2".
  2. 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' ..."
  3. David Frech. "muforth readme". section "Simple and tail-recursive native compiler".
  4. 4.0 4.1 Steve Heller. "Efficient C/C++ Programming: Smaller, Faster, Better". 2014. Chapter 5: "Do you need an interpreter?" p. 195.
  5. Jean-Paul Tremblay; P. G. Sorenson. "The Theory and Practice of Compiler Writing". 1985. p. 527
  6. "Wireless World: Electronics, Radio, Television, Volume 89". p. 73.
  7. "Byte, Volume 5". 1980. p. 212
  8. Bell, James R. (1973). "Threaded code". Communications of the ACM. 16 (6): 370–372. doi:10.1145/362248.362270.
  9. Moore, Charles H., published remarks in Byte Magazine's Forth Issue
  10. Ertl, Anton. "What is Threaded Code?".
  11. Latendresse, Mario; Feeley, Marc. Generation of Fast Interpreters for Huffman-Compressed Bytecode. Elsevier. CiteSeerX 10.1.1.156.2546.
  12. 12.0 12.1 Busby, Jonathan. "The RPL inner loop explained", "The Museum of HP Calculators", 7 September 2018, Retrieved on 27 December 2019
  13. 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.


बाहरी संबंध