2017-04-19 13 views
8

में coroutines क्या हैं?सी ++ 20 में कोरआउट क्या हैं?

"पैरालेलिज्म 2" या/और "Concurrency2" (छवि के नीचे देखें) से अलग तरीके से यह किस तरह से अलग है?

नीचे दी गई छवि आईएसओसीपीपी से है।

https://isocpp.org/files/img/wg21-timeline-2017-03.png

enter image description here

+3

जवाब देने के लिए "* समरूपता * और * समरूपता * से अलग * कोरआउट * की अवधारणा किस तरह से है?" - https://en.wikipedia.org/wiki/Coroutine –

+0

संबंधित: http://stackoverflow.com/q/35121078/103167 –

+3

कोरआउट के लिए एक बहुत अच्छा और आसान-अनुसरण करने वाला परिचय जेम्स मैकनेलिस की प्रस्तुति "परिचय है सी ++ कोरोटाइन्स "(सीपीपीकॉन2016)। – philsumuru

उत्तर

20

एक अमूर्त स्तर पर, कोरोटाइन्स निष्पादन का धागा रखने के विचार से निष्पादन स्थिति को बंद करने के विचार को विभाजित करते हैं।

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

थ्रेडिंग में कई "निष्पादन के धागे" और एकाधिक निष्पादन राज्य हैं। आपके पास एक से अधिक कार्यक्रम हैं, और निष्पादन के एक से अधिक धागे हैं।

कोरआउट में कई निष्पादन राज्य हैं, लेकिन निष्पादन के धागे का मालिक नहीं है। आपके पास एक कार्यक्रम है, और कार्यक्रम में राज्य है, लेकिन इसमें निष्पादन का कोई धागा नहीं है।


कोरआउट के सबसे आसान उदाहरण जेनरेटर या अन्य भाषाओं से गणित हैं।

छद्म कोड में:

function Generator() { 
    for (i = 0 to 100) 
    produce i 
} 

Generator कहा जाता है, और पहली बार यह कहा जाता है 0 देता है। इसका राज्य याद किया जाता है (कोरटाइन के कार्यान्वयन के साथ कितना राज्य बदलता है), और अगली बार जब आप इसे कॉल करते हैं तो यह जारी रहता है जहां यह छोड़ा जाता है। तो यह अगली बार 1 लौटाता है। फिर 2.

अंततः यह लूप के अंत तक पहुंचता है और फ़ंक्शन के अंत से गिर जाता है; coroutine खत्म हो गया है।(यहां क्या होता है जिस भाषा के बारे में हम बात कर रहे हैं उसके आधार पर भिन्न होता है; पायथन में, यह अपवाद फेंकता है)।

कोरोटाइन्स इस क्षमता को सी ++ में लाते हैं।

दो प्रकार के कोरआउट हैं; ढेर और बेकार।

एक स्टैकलेस कोरआउट केवल अपने राज्य में स्थानीय चर और निष्पादन के स्थान को संग्रहीत करता है।

एक स्टैकफुल कोरआउटिन एक संपूर्ण ढेर (धागे की तरह) स्टोर करता है।

स्टैकलेस कोरआउट बहुत हल्के वजन हो सकते हैं। मैंने जो आखिरी प्रस्ताव पढ़ा वह मूल रूप से आपके काम को लैम्ब्डा की तरह कुछ लिखने में शामिल था; सभी स्थानीय चर किसी ऑब्जेक्ट की स्थिति में जाते हैं, और लेबल का उपयोग उस स्थान से/उस स्थान पर कूदने के लिए किया जाता है जहां कोरआउट "मध्यवर्ती परिणाम" उत्पन्न करता है।

मूल्य बनाने की प्रक्रिया को "उपज" कहा जाता है, क्योंकि कोरआउट्स सहकारी मल्टीथ्रेडिंग की तरह थोड़ा हैं; आप कॉलर को निष्पादन का बिंदु वापस दे रहे हैं।

बूस्ट में स्टैकफुल कोरआउट की एक कार्यान्वयन है; यह आपको आपके लिए उपज करने के लिए एक फ़ंक्शन कॉल करने देता है। Stackful coroutines अधिक शक्तिशाली हैं, लेकिन यह भी अधिक महंगा है।


सरल जनरेटर की तुलना में कोरआउट के लिए और भी कुछ है। आप एक कोरआउटिन में एक कोरआउटिन का इंतजार कर सकते हैं, जो आपको कोरआउट को उपयोगी तरीके से लिखने देता है।

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


सी ++ में कोरआउटिन का विशिष्ट कार्यान्वयन थोड़ा दिलचस्प है।

अपने सबसे बुनियादी स्तर पर, यह सी ++: co_returnco_awaitco_yield पर कुछ कीवर्ड जोड़ता है, साथ ही उनके साथ काम करने वाले कुछ पुस्तकालय प्रकारों के साथ।

एक समारोह उसके शरीर में से एक होने के द्वारा एक कोरआउटिन बन जाता है। तो उनकी घोषणा से वे कार्यों से अलग नहीं हैं।

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

generator<int> get_integers(int start=0, int step=1) { 
    for (int current=start; current+= step) 
    co_yield current; 
} 

co_yield कार्यों निष्पादन निलंबित, भंडार है कि राज्य generator<int> में, तो generator<int> के माध्यम से current का मान देता है:

सरल coroutine एक जनरेटर है।

आप लौटाए गए पूर्णांक पर लूप कर सकते हैं।

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

std::future<std::expected<std::string>> load_data(std::string resource) 
{ 
    auto handle = co_await open_resouce(resource); 
    while(auto line = co_await read_line(handle)) { 
    if (std::optional<std::string> r = parse_data_from_line(line)) 
     co_return *r; 
    } 
    co_return std::unexpected(resource_lacks_data(resource)); 
} 

load_data एक coroutine कि एक std::future उत्पन्न करता है जब नामित संसाधन खोला जाता है और हम बिंदु है जहां हम डेटा का अनुरोध पाया करने के लिए पार्स करने के लिए प्रबंधन है।

open_resource और read_line एस शायद एसिंक कोरआउट हैं जो फ़ाइल खोलते हैं और इससे लाइनें पढ़ते हैं। co_await उनकी प्रगति के लिए load_data की निलंबित और तैयार स्थिति को जोड़ता है।

सी ++ कोरआउट इस से अधिक लचीला होते हैं, क्योंकि वे उपयोगकर्ता-अंतरिक्ष प्रकारों के शीर्ष पर भाषा सुविधाओं के न्यूनतम सेट के रूप में कार्यान्वित किए जाते हैं। उपयोगकर्ता के अंतरिक्ष प्रकार प्रभावी रूप से परिभाषित क्या co_returnco_await और co_yieldमतलब - मैंने देखा है कि लोग उसका उपयोग इस तरह के monadic वैकल्पिक भाव लागू करने के लिए है कि एक खाली वैकल्पिक पर एक co_await स्वचालित रूप से बाहरी वैकल्पिक करने के लिए खाली राज्य propogates:

std::optional<int> add(std::optional<int> a, std::optional<int> b) { 
    return (co_await a) + (co_await b); 
} 
बजाय

std::optional<int> add(std::optional<int> a, std::optional<int> b) { 
    if (!a) return std::nullopt; 
    if (!b) return std::nullopt; 
    return *a + *b; 
} 
+0

यह कोरआउट के बारे में सबसे स्पष्ट व्याख्याओं में से एक है मैंने कभी पढ़ा है। उन्हें तुलना और उन्हें सिमड और शास्त्रीय धागे से अलग करना एक उत्कृष्ट विचार था। – Omnifarious

1

coroutines (सी ++ में) कार्य को पूर्ण होने में और प्रदान करने के लिए जो कुछ भी के लिए आवश्यक है कुछ अन्य दिनचर्या के लिए "इंतज़ार" करने में सक्षम हैं होना चाहिए रहे हैं निलंबित, रुका हुआ है, इंतज़ार कर , नियमित करने के लिए नियमित। सी ++ लोगों के लिए सबसे दिलचस्प विशेषता यह है कि कोरआउट्स आदर्श रूप से कोई स्टैक स्पेस नहीं लेते हैं ... सी # पहले से ही इस तरह की प्रतीक्षा और उपज के साथ ऐसा कर सकता है लेकिन सी ++ को इसे पाने के लिए पुनर्निर्मित करना पड़ सकता है।

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

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

+4

चिंताओं की समेकन और अलगाव * पूरी तरह से * असंबंधित हैं। कोरआउट इन निलंबित दिनचर्या के लिए जानकारी प्रदान नहीं कर रहे हैं, वे * पुन: शुरू करने योग्य दिनचर्या हैं। –

2

एक coroutine एक सी समारोह है जो कई वापसी बयान है और जब कहा जाता है एक 2 बार समारोह के शुरू में, लेकिन पहले निर्देश वायुसेना में निष्पादन शुरू नहीं करता है की तरह है पिछली निष्पादित वापसी के दौरान। यह निष्पादन स्थान सभी स्वचालित चर के साथ एक साथ सहेजा जाता है जो गैर कोरआउट कार्यों में ढेर पर रहते हैं।

माइक्रोसॉफ्ट से पिछले प्रयोगात्मक कोरआउटिन कार्यान्वयन ने कॉपी किए गए ढेर का उपयोग किया ताकि आप गहरे घोंसले वाले कार्यों से भी लौट सकें। लेकिन इस संस्करण को सी ++ समिति ने खारिज कर दिया था। आप बूस्ट्स फाइबर लाइब्रेरी के साथ उदाहरण के लिए यह कार्यान्वयन प्राप्त कर सकते हैं।

संबंधित मुद्दे