एक "कोरआउट" और एक "थ्रेड" के बीच अंतर?


जवाबों:


122

Coroutines अनुक्रमिक प्रसंस्करण का एक रूप है: केवल एक किसी भी समय निष्पादित हो रहा है (जैसे सबरूटीन्स AKA प्रक्रिया AKA कार्य करता है - वे सिर्फ एक दूसरे के बीच अधिक तरल रूप से बैटन पास करते हैं)।

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


188

पहले पढ़ें: समरूपता बनाम समानतावाद - क्या अंतर है?

इंटरएक्टिव निष्पादन प्रदान करने के लिए कंसीडर कार्यों का पृथक्करण है। समानांतरता गति बढ़ाने के लिए काम के कई टुकड़ों का एक साथ निष्पादन है। - https://github.com/servo/servo/wiki/Design

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

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

थ्रेड्स के विपरीत, जो पूर्व-खाली हैं, कॉरटीन स्विच सहकारी हैं (प्रोग्रामर नियंत्रण जब एक स्विच होगा)। कर्नेल कोरटाइन स्विच में शामिल नहीं है। - http://www.boost.org/doc/libs/1_55_0/libs/coroutine/doc/html/coroutine/overview.html

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

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

एक एकल प्रोसेसर मशीन पर, थ्रेड्स को तानकर और प्रीमिटेड (बीच में स्विच किया जाता है) (लिनक्स पर डिफ़ॉल्ट टाइमस्लाइज़ 100ms है) जो उन्हें समवर्ती बनाता है। हालाँकि, उन्हें समानांतर (एक साथ) में नहीं चलाया जा सकता है, क्योंकि सिंगल-कोर प्रोसेसर एक समय में केवल एक ही चीज़ चला सकता है।

सहकारी कार्यों को कार्यान्वित करने के लिए कोराउटाइंस और / या जनरेटर का उपयोग किया जा सकता है। कर्नेल थ्रेड्स पर चलने और ऑपरेटिंग सिस्टम द्वारा शेड्यूल किए जाने के बजाय, वे प्रोग्रामर द्वारा निर्धारित अन्य कार्यों के लिए उपज या खत्म होने तक एक ही थ्रेड में चलते हैं। जनरेटर के साथ भाषाएं , जैसे कि पायथन और ईसीएमएस्क्रिप्ट 6, का उपयोग कॉरआउट बनाने के लिए किया जा सकता है। Async / wait (C #, Python, ECMAscript 7, Rust में देखा गया) एक एब्स्ट्रैक्शन है जो जनरेटर कार्यों के शीर्ष पर बनाया गया है जो वायदा / वादा करता है।

कुछ संदर्भों में, coroutines स्टैकफुल फ़ंक्शन को संदर्भित कर सकता है जबकि जनरेटर स्टैकलेस फ़ंक्शन को संदर्भित कर सकता है।

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

उदाहरण के लिए, जावा में " हरे धागे " थे; ये थ्रेड्स थे जो मूल ऑपरेटिंग सिस्टम के कर्नेल थ्रेड्स पर मूल रूप से जावा वर्चुअल मशीन (JVM) द्वारा निर्धारित किए गए थे। ये समानांतर में नहीं चलते थे या कई प्रोसेसर / कोर का लाभ नहीं लेते थे - क्योंकि इसके लिए एक देशी धागे की आवश्यकता होती है! चूंकि वे ओएस द्वारा निर्धारित नहीं किए गए थे, इसलिए वे कर्नेल थ्रेड्स की तुलना में कोरआउट्स अधिक पसंद करते थे। हरे रंग के धागे हैं जो जावा का उपयोग तब तक किया जाता है जब तक कि देशी धागे जावा 1.2 में पेश नहीं किए गए थे।

धागे संसाधनों का उपभोग करते हैं। JVM में, प्रत्येक थ्रेड का अपना स्टैक होता है, आमतौर पर आकार में 1MB। 64k JVM में प्रति थ्रेड अनुमति दी गई स्टैक स्पेस की कम से कम राशि है। थ्रेड स्टैक आकार JVM के लिए कमांड लाइन पर कॉन्फ़िगर किया जा सकता है। नाम के बावजूद, थ्रेड्स मुक्त नहीं हैं, क्योंकि उनके उपयोग के संसाधनों के कारण प्रत्येक थ्रेड को अपने स्वयं के स्टैक, थ्रेड-लोकल स्टोरेज (यदि कोई हो), और थ्रेड शेड्यूलिंग / संदर्भ-स्विचिंग / सीपीयू कैश अमान्य की लागत की आवश्यकता होती है। यह इस कारण का कारण है कि कोराउटाइन प्रदर्शन महत्वपूर्ण, अत्यधिक-समवर्ती अनुप्रयोगों के लिए लोकप्रिय हो गए हैं।

मैक ओएस केवल लगभग 2000 थ्रेड्स को आवंटित करने के लिए एक प्रक्रिया की अनुमति देगा, और लिनक्स प्रति धागे 8MB स्टैक आवंटित करता है और केवल उन कई थ्रेड्स की अनुमति देगा जो भौतिक रैम में फिट होंगे।

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


2
+1, लेकिन यह उत्तर कुछ संदर्भों से लाभान्वित हो सकता है।
कोजीरो

1
हरे धागे कोरटाइन्स की तुलना में कुछ अलग हैं। क्या वे नहीं हैं? यहां तक ​​कि तंतुओं में कुछ अंतर हैं। प्रोग्रामर

112

लगभग 7 साल की देरी से, लेकिन यहाँ जवाब सह-रूट बनाम थ्रेड पर कुछ संदर्भ याद कर रहे हैं। कोरटाइन हाल ही में इतना ध्यान क्यों प्राप्त कर रहे हैं , और मैं थ्रेड्स की तुलना में उनका उपयोग कब करूंगा ?

सबसे पहले अगर कॉरटाइन समवर्ती ( समानांतर में कभी नहीं ) चलाते हैं , तो कोई उन्हें थ्रेड्स पर क्यों पसंद करेगा?

इसका उत्तर यह है कि कॉरटाइन्स बहुत कम ओवरहेड के साथ बहुत उच्च स्तर की संगामिति प्रदान कर सकते हैं । आमतौर पर थ्रेडेड वातावरण में आपके पास सबसे अधिक 30-50 धागे होते हैं, इससे पहले कि ओवरहेड की मात्रा बर्बाद हो जाती है, वास्तव में इन थ्रेड्स को शेड्यूल करना (सिस्टम शेड्यूलर द्वारा) थ्रेड्स वास्तव में उपयोगी काम करने के समय में काफी कटौती करते हैं।

ठीक है, थ्रेड्स के साथ आप समानताएँ रख सकते हैं, लेकिन बहुत अधिक समानता नहीं, क्या यह अभी भी एक धागे में चलने वाली सह-दिनचर्या से बेहतर नहीं है? खैर जरूरी नहीं। याद रखें कि सह-दिनचर्या अभी भी शेड्यूलर ओवरहेड के बिना संगति कर सकती है - यह केवल संदर्भ-स्विचिंग का प्रबंधन करती है।

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

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

क्योंकि आपकी दिनचर्या अब एक-दूसरे के पूर्व-निर्धारित बिंदुओं के बीच बदल जाती है, अब आप साझा डेटा संरचनाओं पर लॉक करने से भी बच सकते हैं (क्योंकि आप कभी भी किसी महत्वपूर्ण अनुभाग के बीच में अन्य कॉरआउट में जाने के लिए अपना कोड नहीं बताएंगे)

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

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


2
जब हम एक अवरुद्ध ऑपरेशन का सामना करते हैं तो कोरटाइन में किसी अन्य कार्य के लिए स्विचिंग कैसे करें?
Narcisse Doudieu Siewe

जिस तरह से आप किसी अन्य कार्य के लिए स्विच करते हैं वह वास्तव में किसी भी अवरुद्ध ऑपरेशन को करना है। इसका मतलब है कि आपको किसी भी ऑपरेशन का उपयोग करने से बचना होगा जो वास्तव में अवरुद्ध हो जाएगा, और केवल उन ऑपरेशनों का उपयोग करें जो आपके कोरटाइन सिस्टम में उपयोग किए जाने पर अवरुद्ध न होने का समर्थन करते हैं। इसके चारों ओर एकमात्र तरीका कर्नेल द्वारा समर्थित कोरटाइन है, जैसे कि उदाहरण के लिए विंडोज पर UMS, जहां यह आपके शेड्यूलर में कूदता है जब भी आपका UMS "syscall पर" ब्लॉक होता है।
रेटेप 88

@MartinKonecny ​​हाल ही में सी ++ थ्रेड्स टीएस आपके द्वारा बताए गए दृष्टिकोण का पालन कर रहा है?
निकोस

तो आखिरकार एक आधुनिक प्रोग्रामिंग भाषा को Coroutines / Fibers दोनों की आवश्यकता होगी, जो कि कुशलतापूर्वक सही हासिल करने के लिए कई कोर पर CPU गहन संचालन को समानांतर करने के लिए IO और Threads जैसे गैर-संगणना-भारी संचालन के लिए कुशलतापूर्वक एकल CPU कोर का उपयोग करें?
महात्मा_फैटल_रूट

19

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

कई थ्रेड कार्यान्वयन वास्तव में कॉरआउट्स की तरह हैं।


9

यह उस भाषा पर निर्भर करता है जिसका आप उपयोग कर रहे हैं। उदाहरण के लिए लुआ में वे एक ही चीज हैं (एक कोरटाइन के परिवर्तनशील प्रकार को कहा जाता है thread)।

आमतौर पर हालांकि, कोरटाइन स्वैच्छिक उपज को लागू करते हैं जहां (आप) प्रोग्रामर तय करता है कि कहां yield, यानी, एक और दिनचर्या को नियंत्रण दें।

इसके बजाय थ्रेड्स स्वचालित रूप से ओएस द्वारा प्रबंधित (बंद और शुरू) किए जाते हैं, और वे मल्टीकोर सीपीयू पर एक ही समय में भी चल सकते हैं।


0

चर्चा में 12 साल देर हो गई लेकिन एक कोरटाइन ने नाम में स्पष्टीकरण दिया। Coroutine को Co और Routine में विघटित किया जा सकता है।

इस संदर्भ में एक रूटीन केवल संचालन / क्रियाओं का एक क्रम है और एक रूटीन को क्रियान्वित / संसाधित करके, अनुक्रमों का क्रम निर्दिष्ट के अनुसार एक-एक करके एक-एक करके निष्पादित होता है।

सह सहयोग के लिए खड़ा है। एक सह दिनचर्या के लिए कहा जाता है (या बेहतर की उम्मीद) स्वेच्छा से अपने निष्पादन को निलंबित करने के लिए अन्य सह-दिनचर्या को भी निष्पादित करने का मौका देता है। इसलिए सह-दिनचर्या सीपीयू संसाधनों (स्वेच्छा से) को साझा करने के बारे में है ताकि अन्य उसी संसाधन का उपयोग कर सकें जो स्वयं का उपयोग कर रहा है।

दूसरी ओर एक धागा को इसके निष्पादन को निलंबित करने की आवश्यकता नहीं है। निलंबित किया जाना धागे के लिए पूरी तरह से पारदर्शी है और धागा अंतर्निहित हार्डवेयर द्वारा खुद को निलंबित करने के लिए मजबूर किया जाता है। यह एक तरीके से भी किया जाता है ताकि यह धागे के लिए अधिकांशतः पारदर्शी हो क्योंकि यह अधिसूचित नहीं होता है और इसकी स्थिति में कोई बदलाव नहीं होता है लेकिन सहेजा जाता है और बाद में बहाल किया जाता है जब धागा जारी रखने की अनुमति होती है।

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

इससे कोई फर्क नहीं पड़ता कि सह-दिनचर्या खुद को कैसे निलंबित करती है। वापस विंडोज 3.1 इंट 03 में किसी भी कार्यक्रम में बुना गया था (या वहां रखा जाना था) और सी # में हम उपज जोड़ते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.