60/70 के दशक में कॉरटाइन्स के लिए अधिकांश ग्राउंडवर्क हुआ और फिर विकल्प (जैसे, धागे) के पक्ष में रुके
क्या पायथन और अन्य भाषाओं में होने वाले कोराउटीनों में नए सिरे से कोई दिलचस्पी है?
60/70 के दशक में कॉरटाइन्स के लिए अधिकांश ग्राउंडवर्क हुआ और फिर विकल्प (जैसे, धागे) के पक्ष में रुके
क्या पायथन और अन्य भाषाओं में होने वाले कोराउटीनों में नए सिरे से कोई दिलचस्पी है?
जवाबों:
Coroutines ने कभी नहीं छोड़ा, वे बस इस बीच अन्य चीजों से प्रभावित थे। एसिंक्रोनस प्रोग्रामिंग में हाल ही में बढ़ी हुई रुचि और इसलिए कॉरटाइन तीन कारकों के कारण काफी हद तक है: कार्यात्मक प्रोग्रामिंग तकनीकों की बढ़ती स्वीकृति, सच्चे समानता के लिए खराब समर्थन के साथ टूलसेट (जावास्क्रिप्ट! पायथन!), और सबसे महत्वपूर्ण बात: थ्रेड्स और कॉरटाइन के लिए अलग-अलग ट्रेडऑफ़। कुछ उपयोग मामलों के लिए, कोराउटीन उद्देश्यपूर्ण रूप से बेहतर हैं।
80, 90 और आज के सबसे बड़े प्रोग्रामिंग प्रतिमानों में से एक ओओपी है। यदि हम OOP के इतिहास को देखते हैं और विशेष रूप से सिमाला भाषा के विकास को देखते हैं, तो हम देखते हैं कि कक्षाएं कोरआउट से विकसित हुई हैं। असतत घटनाओं के साथ सिस्टम के अनुकरण के लिए सिमूला का इरादा था। सिस्टम का प्रत्येक तत्व एक अलग प्रक्रिया थी जो एक सिमुलेशन कदम की अवधि के लिए घटनाओं के जवाब में निष्पादित करेगा, फिर अन्य प्रक्रियाओं को अपना काम करने देने के लिए उपज। सिमाला 67 के विकास के दौरान वर्ग अवधारणा पेश की गई थी। अब कॉरटीन की लगातार स्थिति को ऑब्जेक्ट सदस्यों में संग्रहीत किया जाता है, और एक विधि को कॉल करके घटनाओं को चालू किया जाता है। अधिक जानकारी के लिए, पेपर को पढ़ने पर विचार करें । न्यागार्ड और डाहल द्वारा SIMULA भाषाओं का विकास ।
इसलिए एक मजेदार मोड़ में हम सभी के साथ कॉरआउट का उपयोग कर रहे हैं, हम बस उन्हें ऑब्जेक्ट्स और इवेंट-संचालित प्रोग्रामिंग कह रहे थे।
समानता के संबंध में, दो प्रकार की भाषाएं हैं: वे जो एक उचित मेमोरी मॉडल हैं, और जो नहीं हैं। एक स्मृति मॉडल "अगर मैं एक चर में लिखता हूं और उसके बाद दूसरे चर में उस चर से पढ़ता हूं, तो क्या मैं पुराने मूल्य या नए मूल्य या शायद एक अमान्य मूल्य देखता हूं? 'पहले' और 'बाद' का क्या अर्थ है? कौन से ऑपरेशन परमाणु होने की गारंटी है? ”
एक अच्छी मेमोरी मॉडल बनाना मुश्किल है, इसलिए यह प्रयास कभी भी इनमें से अधिकांश अनिर्दिष्ट, कार्यान्वयन-परिभाषित गतिशील ओपन-सोर्स भाषाओं के लिए नहीं किया गया है: पर्ल, जावास्क्रिप्ट, पायथन, रूबी, पीएचपी। बेशक, उन सभी भाषाओं को "स्क्रिप्टिंग" से परे विकसित किया गया था जो कि वे मूल रूप से बनाए गए थे। खैर, इनमें से कुछ भाषाओं में कुछ प्रकार के मेमोरी मॉडल दस्तावेज़ हैं, लेकिन वे पर्याप्त नहीं हैं। इसके बजाय, हमारे पास हैक हैं:
पर्ल को थ्रेडिंग समर्थन के साथ संकलित किया जा सकता है, लेकिन प्रत्येक थ्रेड में पूर्ण दुभाषिया राज्य का एक अलग क्लोन होता है, जिससे धागे निषेधात्मक रूप से महंगे हो जाते हैं। एकमात्र लाभ के रूप में, यह साझा-कुछ भी दृष्टिकोण डेटा दौड़ से बचा जाता है, और प्रोग्रामर को केवल कतारों / संकेतों / आईपीसी के माध्यम से संवाद करने के लिए मजबूर करता है। पर्ल के पास async प्रसंस्करण के लिए एक मजबूत कहानी नहीं है।
जावास्क्रिप्ट को हमेशा कार्यात्मक प्रोग्रामिंग के लिए समृद्ध समर्थन मिला है, इसलिए प्रोग्रामर मैन्युअल रूप से अपने कार्यक्रमों में निरंतरता / कॉलबैक को सांकेतिक शब्दों में बदलना होगा जहां उन्हें अतुल्यकालिक संचालन की आवश्यकता होती है। उदाहरण के लिए, अजाक्स अनुरोध या एनीमेशन देरी के साथ। चूंकि वेब स्वाभाविक रूप से async है, इसलिए बहुत से async जावास्क्रिप्ट कोड हैं और इन सभी कॉलबैक को प्रबंधित करना बेहद दर्दनाक है। इसलिए हम उन कॉलबैक को बेहतर तरीके से (प्रोमिस) व्यवस्थित करने या उन्हें पूरी तरह से खत्म करने के कई प्रयास देखते हैं।
पायथन में यह दुर्भाग्यपूर्ण विशेषता है जिसे ग्लोबल इंटरप्रेटर लॉक कहा जाता है। मूल रूप से पायथन मेमोरी मॉडल है "सभी प्रभाव क्रमिक रूप से दिखाई देते हैं क्योंकि कोई समानता नहीं है। एक समय में केवल एक धागा पायथन कोड चलाएगा। ”जबकि पायथन के पास थ्रेड्स हैं, लेकिन ये केवल टाउटाइन के रूप में शक्तिशाली हैं। [१] पाइथन जनरेटर के कार्यों के माध्यम से कई कोरटाइन को सांकेतिक शब्दों में बदलना कर सकता है yield
। अगर सही तरीके से इस्तेमाल किया जाए, तो यह अकेले जावास्क्रिप्ट से जाने जाने वाले कॉलबैक नरक से बचा सकता है। पायथन 3.5 से अधिक हाल ही में async / प्रतीक्षा प्रणाली पायथन में अतुल्यकालिक मुहावरों को अधिक सुविधाजनक बनाती है, और एक घटना लूप को एकीकृत करती है।
[१]: तकनीकी रूप से ये प्रतिबंध केवल सीपीथॉन पर लागू होते हैं, पायथन संदर्भ कार्यान्वयन। Jython जैसे अन्य कार्यान्वयन वास्तविक धागे की पेशकश करते हैं जो समानांतर में निष्पादित कर सकते हैं, लेकिन समान व्यवहार को लागू करने के लिए महान लंबाई से गुजरना पड़ता है। अनिवार्य रूप से: प्रत्येक चर या वस्तु सदस्य एक अस्थिर चर है जिससे सभी परिवर्तन परमाणु होते हैं और तुरंत सभी थ्रेड्स में देखे जाते हैं। बेशक, अस्थिर चर का उपयोग करना सामान्य चर का उपयोग करने की तुलना में कहीं अधिक महंगा है।
मैं रूबी और PHP के बारे में पर्याप्त रूप से नहीं जानता कि उन्हें ठीक से भुना जाए।
संक्षेप में प्रस्तुत करने के लिए: इनमें से कुछ भाषाओं में मौलिक डिजाइन निर्णय हैं जो बहुउद्देशीय को अवांछनीय या असंभव बनाते हैं, जिससे कोरटाइन जैसे विकल्पों पर अधिक ध्यान केंद्रित होता है और एसिंक्स प्रोग्रामिंग को और अधिक सुविधाजनक बनाने के तरीकों पर।
अंत में, आइए कोरटाइन और थ्रेड्स के बीच अंतर के बारे में बात करते हैं:
थ्रेड्स मूल रूप से प्रक्रियाओं की तरह होते हैं, सिवाय इसके कि एक प्रक्रिया के अंदर कई थ्रेड्स एक मेमोरी स्पेस साझा करते हैं। इसका मतलब है कि थ्रेड्स स्मृति के संदर्भ में "हल्के वजन" से नहीं हैं। ऑपरेटिंग सिस्टम द्वारा थ्रेड्स पूर्व-निर्धारित हैं। इसका मतलब है कि कार्य स्विच में एक उच्च ओवरहेड है, और असुविधाजनक समय पर हो सकता है। इस ओवरहेड में दो घटक होते हैं: थ्रेड की स्थिति को निलंबित करने की लागत, और उपयोगकर्ता मोड (थ्रेड के लिए) और कर्नेल मोड (अनुसूचक के लिए) के बीच स्विच करने की लागत।
यदि कोई प्रक्रिया अपने स्वयं के थ्रेड को सीधे और सहकारी रूप से शेड्यूल करती है, तो कर्नेल मोड में संदर्भ स्विच अनावश्यक है, और स्विचिंग कार्य समान रूप से अप्रत्यक्ष फ़ंक्शन कॉल के लिए महंगा है, जैसे: काफी सस्ता। इन हल्के वजन के धागों को विभिन्न विवरणों के आधार पर हरे रंग के धागे, रेशे या कोरटाइन कहा जा सकता है। हरे रंग के धागे / तंतुओं के उल्लेखनीय उपयोगकर्ता प्रारंभिक जावा कार्यान्वयन थे, और हाल ही में गोलंग में गोरोटाइन्स। कोरआउटों का एक वैचारिक लाभ यह है कि उनके निष्पादन को नियंत्रण प्रवाह के संदर्भ में समझा जा सकता है जो स्पष्ट रूप से कोरटाइन के बीच आगे और पीछे से गुजरते हैं। हालाँकि, ये कोरआउट तब तक सही समानता नहीं प्राप्त करते हैं जब तक कि वे कई OS थ्रेड्स में शेड्यूल नहीं किए जाते हैं।
सस्ते कोराउटीन कहां उपयोगी हैं? अधिकांश सॉफ्टवेयर को एक गजियन थ्रेड्स की आवश्यकता नहीं होती है, इसलिए सामान्य महंगे धागे आमतौर पर ठीक होते हैं। हालाँकि, async प्रोग्रामिंग कभी-कभी आपके कोड को सरल बना सकती है। स्वतंत्र रूप से उपयोग किए जाने के लिए, इस अमूर्त को पर्याप्त रूप से सस्ता होना चाहिए।
और फिर वेब है। जैसा कि ऊपर उल्लेख किया गया है, वेब स्वाभाविक रूप से अतुल्यकालिक है। नेटवर्क अनुरोधों को बस एक लंबा समय लगता है। कई वेब सर्वर वर्कर थ्रेड से भरे थ्रेड पूल को बनाए रखते हैं। हालांकि, उनके अधिकांश समय ये धागे बेकार होंगे क्योंकि वे किसी संसाधन की प्रतीक्षा कर रहे हैं, क्या यह एक I / O घटना की प्रतीक्षा कर रहा है जब डिस्क से एक फ़ाइल लोड हो रही है, तब तक प्रतीक्षा करना जब तक कि ग्राहक ने प्रतिक्रिया का हिस्सा स्वीकार नहीं किया है, या एक डेटाबेस तक इंतजार कर रहा है। क्वेरी पूरी होती है। NodeJS ने असाधारण रूप से प्रदर्शित किया है कि एक परिणामी घटना-आधारित और अतुल्यकालिक सर्वर डिजाइन बहुत अच्छी तरह से काम करता है। जाहिर है कि जावास्क्रिप्ट वेब अनुप्रयोगों के लिए उपयोग की जाने वाली एकमात्र भाषा से दूर है, इसलिए अतुल्यकालिक वेब प्रोग्रामिंग को आसान बनाने के लिए अन्य भाषाओं (पायथन और सी # में ध्यान देने योग्य) के लिए एक बड़ा प्रोत्साहन भी है।
Coroutines उपयोगी हुआ करती थी क्योंकि ऑपरेटिंग सिस्टम पूर्व-खाली समय - निर्धारण नहीं करता था । एक बार जब वे पूर्व-समयबद्ध शेड्यूल प्रदान करना शुरू कर देते हैं, तो आपके कार्यक्रम में समय-समय पर नियंत्रण छोड़ना आवश्यक था।
जैसे ही मल्टी-कोर प्रोसेसर अधिक प्रचलित हो जाते हैं, कोरटाइन का उपयोग टास्क समानता को प्राप्त करने और / या सिस्टम के उपयोग को उच्च रखने के लिए किया जाता है (जब निष्पादन के एक धागे को एक संसाधन पर इंतजार करना चाहिए, तो दूसरा इसके स्थान पर चलना शुरू कर सकता है)।
NodeJS एक विशेष मामला है, जहाँ कोरटाइन का उपयोग IO के समानांतर किया जाता है। यही है, IO अनुरोधों की सेवा के लिए कई थ्रेड्स का उपयोग किया जाता है, लेकिन जावास्क्रिप्ट कोड को निष्पादित करने के लिए एक एकल थ्रेड का उपयोग किया जाता है। एक सांकेतिक धागे में एक उपयोगकर्ता कोड को निष्पादित करने का उद्देश्य म्यूटेक्स का उपयोग करने की आवश्यकता से बचने के लिए है। यह सिस्टम के उपयोग को ऊपर बताए अनुसार रखने की कोशिश की श्रेणी में आता है।
प्रारंभिक प्रणालियों ने मुख्य रूप से संगामिति प्रदान करने के लिए कोरटाइन का उपयोग किया क्योंकि वे इसे करने का सबसे सरल तरीका हैं। थ्रेड्स को ऑपरेटिंग सिस्टम से उचित मात्रा में समर्थन की आवश्यकता होती है (आप उन्हें एक उपयोगकर्ता स्तर पर लागू कर सकते हैं, लेकिन आपको समय-समय पर अपनी प्रक्रिया को बाधित करने के लिए सिस्टम की व्यवस्था करने के कुछ तरीके की आवश्यकता होगी) और आपके पास समर्थन होने पर भी लागू करना कठिन है ।
थ्रेड्स ने बाद में आगे बढ़ना शुरू कर दिया क्योंकि 70 या 80 के दशक तक सभी गंभीर ऑपरेटिंग सिस्टम ने उनका समर्थन किया (और, 90 के दशक तक, यहां तक कि विंडोज भी!), और वे अधिक सामान्य हैं। और वे उपयोग करने के लिए आसान कर रहे हैं। अचानक सभी ने सोचा कि धागे अगली बड़ी चीज हैं।
90 के दशक के अंत तक दरारें दिखाई देने लगी थीं, और 2000 के दशक की शुरुआत में यह स्पष्ट हो गया कि थ्रेड्स के साथ गंभीर समस्याएं थीं:
समय के साथ, कार्य कार्यक्रमों की संख्या में आमतौर पर किसी भी समय प्रदर्शन करने की आवश्यकता होती है, तेजी से बढ़ रहा है, जिससे (1) और (2) के कारण होने वाली समस्याएं बढ़ रही हैं। प्रोसेसर की गति और मेमोरी एक्सेस समय के बीच असमानता बढ़ती जा रही है, समस्या (3) बढ़ रही है। और समस्या की प्रासंगिकता को बढ़ाते हुए, कितने और किस प्रकार के संसाधनों की आवश्यकता के संदर्भ में कार्यक्रमों की जटिलता बढ़ रही है।
लेकिन थोड़ी सी सामान्यता को खो कर, और प्रोग्रामर पर थोड़ा अतिरिक्त ओन्स लगाकर यह सोचने के लिए कि उनकी प्रक्रियाएं एक साथ कैसे चल सकती हैं, कोरटाइन इन सभी समस्याओं को हल कर सकता है।
मैं एक कारण बताते हुए शुरुआत करना चाहता हूं कि कोरटाइन को पुनरुत्थान, समानता नहीं मिल रही है। सामान्य तौर पर आधुनिक कोराउटाइन कार्य आधारित समानता प्राप्त करने का साधन नहीं हैं , क्योंकि आधुनिक कार्यान्वयन मल्टीप्रोसेसिंग कार्यक्षमता का उपयोग नहीं करते हैं। सबसे पास की चीज़ जो आपको मिलती है वो है फाइबर जैसी चीज़ें ।
आधुनिक कोरआउट्स आलसी मूल्यांकन को प्राप्त करने का एक तरीका बन गए हैं, हैस्केल जैसी कार्यात्मक भाषाओं में कुछ बहुत उपयोगी है, जहां एक ऑपरेशन करने के लिए पूरे सेट पर पुनरावृत्ति करने के बजाय, आप केवल एक ऑपरेशन का मूल्यांकन करने में सक्षम होंगे जितना आवश्यक हो () आइटम के अनंत सेटों के लिए उपयोगी या अन्यथा प्रारंभिक समाप्ति और सबसेट के साथ बड़े सेट)।
पायथन और C # जैसी भाषाओं में जनरेटर बनाने के लिए यील्ड कीवर्ड के उपयोग के साथ (जो स्वयं में आलसी मूल्यांकन की जरूरत को पूरा करता है), आधुनिक कार्यान्वयन में, कोरआउट, न केवल संभव थे, बल्कि भाषा में ही विशेष वाक्य रचना के साथ संभव थे। (हालांकि अजगर ने अंततः मदद करने के लिए कुछ बिट्स जोड़े)। सह दिनचर्या के विचार के साथ आलसी evaulation के साथ मदद के भविष्य रों जहां अगर आप उस समय एक चर के मूल्य की जरूरत नहीं है, आप वास्तव में यह प्राप्त जब तक आप स्पष्ट रूप से है कि मूल्य के लिए पूछना विलंब कर सकते हैं (आप मान का उपयोग करने की इजाजत दी और lazily तात्कालिकता से अलग समय पर इसका मूल्यांकन करें )।
आलसी मूल्यांकन से परे, हालांकि, विशेष रूप से websphere में, ये सह दिनचर्या कॉलबैक नरक को ठीक करने में मदद करती हैं । डेटाबेस एक्सेस, ऑनलाइन ट्रांजेक्शन, यूआई इत्यादि में कोराटाइन्स उपयोगी हो जाते हैं, जहाँ क्लाइंट मशीन पर प्रोसेसिंग का समय ही नहीं लगता कि आपको क्या चाहिए। थ्रेडिंग एक ही चीज़ को पूरा कर सकती है, लेकिन इस क्षेत्र में बहुत अधिक ओवरहेड की आवश्यकता होती है, और कोरटाइन के विपरीत, वास्तव में कार्य समानता के लिए उपयोगी होते हैं ।
संक्षेप में, जैसा कि वेब विकास बढ़ता है और कार्यात्मक प्रतिमानों का अनिवार्यता के साथ अधिक विलय हो जाता है, कोरटाइन अतुल्यकालिक समस्याओं और आलसी मूल्यांकन के समाधान के रूप में आए हैं। Coroutines समस्या वाले स्थानों पर आती है जहाँ मल्टीप्रोसेसिंग थ्रेडिंग और थ्रेडिंग सामान्य रूप से अनावश्यक, असुविधाजनक या संभव नहीं होते हैं।
Javascript, Lua, C # और Python जैसी भाषाओं में Coroutines सभी अपने कार्यों को अलग-अलग कार्यों द्वारा मुख्य कार्यों को नियंत्रित करने वाले अन्य कार्यों (ऑपरेटिंग सिस्टम कॉल के साथ कुछ नहीं करना) द्वारा उनके कार्यान्वयन को प्राप्त करती हैं ।
में इस अजगर उदाहरण के लिए, हम कुछ कहा के साथ एक अजीब अजगर समारोह है await
जिसके भीतर। यह मूल रूप से एक पैदावार है, जो निष्पादन को पैदावार loop
देता है, फिर एक अलग फ़ंक्शन को चलाने की अनुमति देता है (इस मामले में, एक अलग factorial
फ़ंक्शन)। ध्यान दें कि जब यह कहता है कि "कार्यों का समानांतर निष्पादन" जो एक मिथ्या नाम है, तो यह वास्तव में समानांतर में निष्पादित नहीं हो रहा है, प्रतीक्षारत कीवर्ड के उपयोग के माध्यम से इसकी इंटरलेनिविंग फ़ंक्शन निष्पादन (जो ध्यान में रखते हैं कि यह केवल एक विशेष प्रकार की उपज है)
वे एकल, गैर समानांतर, समवर्ती प्रक्रियाओं के लिए नियंत्रण की पैदावार की अनुमति देते हैं जो कि समानांतर कार्य नहीं है , इस अर्थ में कि ये कार्य कभी भी एक ही समय में संचालित नहीं होते हैं । आधुनिक भाषा के कार्यान्वयन में कोरीटीन धागे नहीं हैं । सह रूटीन के इन सभी भाषाओं के कार्यान्वयन इन फ़ंक्शन उपज कॉल (जो आपको प्रोग्रामर को वास्तव में अपने सह रूट में मैन्युअल रूप से डालनी है) से प्राप्त होते हैं।
संपादित करें: C ++ बूस्ट coroutine2 उसी तरह से काम करता है, और आपके विवरण को बेहतर दृश्य देना चाहिए कि मैं किस बारे में यिल्ड्स के साथ बात कर रहा हूं, यहां देखें । जैसा कि आप देख सकते हैं, कार्यान्वयन के साथ कोई "विशेष मामला" नहीं है, बूस्ट फाइबर जैसी चीजें नियम का अपवाद हैं, और तब भी स्पष्ट सिंक्रनाइज़ेशन की आवश्यकता होती है।
EDIT2: क्योंकि किसी ने सोचा था कि मैं c # कार्य आधारित प्रणाली के बारे में बात कर रहा था, मैं नहीं था। मैं एकता की प्रणाली और भोली सी # कार्यान्वयन के बारे में बात कर रहा था