कॉरटीन बनाम कंटीन्यूएशन बनाम जनरेटर


147

कोरटाइन और एक निरंतरता और एक जनरेटर के बीच अंतर क्या है?


2
मुझे आश्चर्य है कि अगर कोरटाइन और निरंतरता प्रभावी रूप से बराबर हैं। मुझे पता है कि निरंतरता के साथ कॉरआउट बनाना संभव है, लेकिन क्या कॉरटाइन के साथ निरंतरता को मॉडल करना संभव है या नहीं क्योंकि निरंतरता अधिक शक्तिशाली होती है?
nalply

जवाबों:


127

मैं जनरेटर के साथ शुरू करूँगा, क्योंकि वे सबसे सरल मामला हैं। जैसा कि @zvolkov ने उल्लेख किया है, वे फ़ंक्शंस / ऑब्जेक्ट्स हैं जिन्हें बार-बार बिना रिटर्न के कॉल किया जा सकता है, लेकिन जब कॉल किया जाता है तो एक वैल्यू (रिटर्न) वापस आ जाएगी और फिर उनके निष्पादन को रोक दिया जाएगा। जब वे फिर से बुलाए जाते हैं, तो वे उस जगह से शुरू करेंगे, जहां से वे अंतिम रूप से निलंबित निष्पादन और फिर से अपनी बात करेंगे।

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

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

def my_coroutine_body(*args):
    while True:
        # Do some funky stuff
        *args = yield value_im_returning
        # Do some more funky stuff

my_coro = make_coroutine(my_coroutine_body)

x = 0
while True:
   # The coroutine does some funky stuff to x, and returns a new value.
   x = my_coro(x)
   print x

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

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

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

बता दें कि पायथन का एक फंक्शन था callcc(), और इस फंक्शन में दो तर्क हुए, पहला एक फंक्शन और दूसरा इसे कहने के लिए तर्कों की लिस्ट। उस फ़ंक्शन पर केवल प्रतिबंध यह होगा कि अंतिम तर्क यह एक फ़ंक्शन होगा (जो हमारी वर्तमान निरंतरता होगी)।

def foo(x, y, cc):
   cc(max(x, y))

biggest = callcc(foo, [23, 42])
print biggest

क्या होता है कि चालू निरंतरता ( ) के साथ callcc()कॉल foo()किया जाता है cc, अर्थात, उस कार्यक्रम के बिंदु का संदर्भ जिस callcc()पर कॉल किया गया था। जब foo()वर्तमान निरंतरता को कॉल करता है, तो यह अनिवार्य रूप callcc()से उस मूल्य के साथ लौटने के लिए कह रहा है जिसे आप वर्तमान निरंतरता के साथ कॉल कर रहे हैं, और जब वह ऐसा करता है, तो यह उस स्टैक को वापस रोल करता है जहां वर्तमान निरंतरता बनाई गई थी, अर्थात, जब आपने कॉल किया था callcc()

इन सबका नतीजा यह होगा कि हमारा काल्पनिक पायथन संस्करण छपेगा '42'

मुझे आशा है कि मदद करता है, और मुझे यकीन है कि मेरी व्याख्या में थोड़ा सुधार किया जा सकता है!


6
एक निट: सीमांकित निरंतरता कार्यों रहे हैं, लेकिन undelimited : निरंतरता नहीं हैं okmij.org/ftp/continuations/undelimited.html#delim-vs-undelim
फ्रैंक Shearar

2
ये एक अच्छा बिंदु है। अधिकांश व्यावहारिक अनुप्रयोगों में, जब लोग कहते हैं कि 'निरंतरता', वे आंशिक / सीमांकित निरंतरता के बारे में बात कर रहे हैं। विभिन्न प्रकार की निरंतरताओं में लाने से स्पष्टीकरण कुछ हद तक स्पष्ट हो जाता है।
कीथ गौघन

1
निरंतरताएं कार्य नहीं हैं, हालांकि उन्हें कार्यों में बदला जा सकता है। "उस ने कहा, अधिकांश व्यावहारिक अनुप्रयोगों में, जब लोग 'निरंतरता' कहते हैं, तो वे आंशिक / सीमांकित निरंतरता के बारे में बात कर रहे हैं।" क्या आप "निरंतरता" शब्द के ऐसे उपयोग की ओर संकेत करेंगे? मैं ऐसे उपयोग से कभी नहीं मिला। इसके अलावा, आपने कॉल / cc का उपयोग करके एक undelimited निरंतरता के लिए एक उदाहरण दिया। सीमांकित निरंतरता के लिए ऑपरेटर आमतौर पर "रीसेट" और "शिफ्ट" होते हैं (उनके अन्य नाम हो सकते हैं)।
इवानो

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

2
मैं पार्टी के लिए देर नहीं कर रहा हूँ क्योंकि यह पहला परिणाम है जो मुझे Google में मिलता है जब मैं "coroutine बनाम जनरेटर" खोजता हूं। मैं उनके अंतर के बारे में कुछ अच्छी जानकारी पाने की उम्मीद कर रहा था। वैसे भी मुझे यह कहीं और मिला। और मैं यह बताने वाला पहला व्यक्ति नहीं हूं कि निरंतरता के बारे में आपका स्पष्टीकरण गलत है। समस्या यह है कि किसी को यह गलत हो जाएगा और संभवतः बाद में भ्रमित हो सकता है जब वह कुछ अलग के लिए इस्तेमाल किए गए एक ही शब्द से मिलता है।
इवानो

33

Coroutine कई प्रक्रियाओं में से एक है जो अपना काम करती है और फिर समूह में अन्य कोरआउट्स को नियंत्रण देने के लिए रुकती है।

निरंतरता एक "एक फ़ंक्शन के लिए सूचक" है जो आप उस प्रक्रिया को पूरा करने पर कुछ प्रक्रिया से गुजरते हैं, निष्पादित किया जाना है ("जारी रखा गया")।

जेनरेटर (.NET में) एक भाषा निर्माण है जो एक मूल्य को थूक सकता है, विधि के "ठहराव" निष्पादन और फिर अगले मूल्य के लिए पूछे जाने पर उसी बिंदु से आगे बढ़ सकता है।


मुझे लगता है कि उत्तर सटीक नहीं हो सकता है लेकिन इस स्तर के प्रश्न पर मैंने इसे सरल रखने की कोशिश की। इसके अलावा, मैं वास्तव में यह सब खुद नहीं समझता हूं :)
zvolkov

अजगर में एक जनरेटर सी # संस्करण के समान है, लेकिन एक इटेरेटर ऑब्जेक्ट की एक आवृत्ति बनाने के लिए एक विशेष वाक्यविन्यास के रूप में लागू किया जाता है, जो आपके द्वारा प्रदान की गई "फ़ंक्शन" परिभाषा द्वारा लौटाए गए मानों को लौटाता है।
बेन्सन

2
एक छोटा सुधार: "... जिसमें कॉल स्टैक और सभी वैरिएबल BUT NOT THEIR VALUES" (या सिर्फ "सभी वैरिएबल") ड्रॉप होते हैं। निरंतरता मूल्यों को संरक्षित नहीं करते हैं, वे सिर्फ कॉल स्टैक होते हैं।
नालपुरी

नहीं, निरंतरता "एक फ़ंक्शन के लिए पॉइंटर" नहीं है। सबसे भोली कार्यान्वयन में, यह कार्य करने के लिए एक सूचक होता है और एक वातावरण स्थानीय चर रखता है। और यह तब तक कभी नहीं लौटता जब तक कि आप रिटर्न वैल्यू के साथ इसे पकड़ने के लिए कॉल / सीसी जैसी किसी चीज का इस्तेमाल नहीं करते।
नलगिन्रूट

9

पायथन के नए संस्करण में, आप जेनरेटरों को मान भेज सकते हैं generator.send(), जिससे अजगर जेनरेटरों को प्रभावी ढंग से कोरटाइन बनाता है।

अजगर जेनरेटर, और अन्य जनरेटर के बीच मुख्य अंतर, ग्रीनलेट कहते हैं, यह है कि अजगर में, yield valueआप केवल कॉलर को वापस कर सकते हैं। ग्रीनलेट में रहते हुए, target.switch(value)आप एक विशिष्ट लक्ष्य कोरआउट में ले जा सकते हैं और एक मान प्राप्त कर सकते हैं जहां targetभागना जारी रहेगा।


3
लेकिन पायथन में, सभी yieldकॉल एक ही फ़ंक्शन में होनी चाहिए, जिसे "जेनरेटर" कहा जाता है। आप yieldउप-फ़ंक्शन से नहीं आ सकते हैं , यही वजह है कि पायथन को अर्ध-कोराउटाइन्स कहा जाता है , जबकि लुआ में असममित कोरआउट होते हैं । (पैदावार का प्रचार करने के प्रस्ताव हैं, लेकिन मुझे लगता है कि वे केवल पानी को गंदा करते हैं।)
cdunn2001

7
@ cdunn2001: (विंस्टन द्वारा टिप्पणी) पायथन 3.3 ने "उपज से" अभिव्यक्ति शुरू की, जो आपको उप-जनरेटर से उपज देती है।
लिनस कैलडवेल 12
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.