हमें async कीवर्ड की आवश्यकता क्यों है?


19

मैंने अभी .Net 4.5 में async / wait के साथ खेलना शुरू किया। एक बात जो मैं शुरू में उत्सुक हूँ, वह है एसिंक्स कीवर्ड क्यों आवश्यक है? मैंने जो स्पष्टीकरण पढ़ा वह यह था कि यह एक मार्कर है इसलिए कंपाइलर जानता है कि एक विधि कुछ इंतजार कर रही है। लेकिन ऐसा लगता है कि संकलक को बिना कीवर्ड के यह पता लगाने में सक्षम होना चाहिए। तो यह और क्या करता है?


2
यहाँ वास्तव में अच्छा ब्लॉग लेख (श्रृंखला) है जो C # में कीवर्ड और F # में संबंधित कार्यक्षमता का वर्णन करते हुए कुछ विवरण में जाता है।
पॉल

मुझे लगता है कि यह मुख्य रूप से डेवलपर के लिए एक मार्कर है, और संकलक के लिए नहीं।
कोडइन्कॉस्ट

8
यह लेख इसे समझाता है: blogs.msdn.com/b/ericlippert/archive/2010/11/11/…
svick

@ धन्यवाद धन्यवाद, यह वही है जिसकी मुझे तलाश थी। अब सही समझ में आता है।
सशर्त

जवाबों:


23

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

यह "एक विशेष तरीके से फ़ंक्शन को बदलने के लिए संकलक को निर्देशित करने के लिए नहीं है"; awaitअकेला ऐसा कर सकता था। क्यों? क्योंकि C # में पहले से ही एक अन्य तंत्र है, जहां विधि निकाय में एक विशेष कीवर्ड की उपस्थिति के कारण कंपाइलर को चरम प्रदर्शन करना पड़ता है (और बहुत समान है)async/await ) परिवर्तनोंyield :।

सिवाय इसके कि yieldC # में अपना कीवर्ड नहीं है, और यह समझने के कारण कि यह भी समझा जाएगा async। इस तंत्र का समर्थन करने वाली अधिकांश भाषाओं के विपरीत, C # में आप यह नहीं कह सकते कि yield value;आपको yield return value;इसके बजाय कहना है । क्यों? क्योंकि यह C # पहले से मौजूद होने के बाद भाषा में जोड़ा गया था, और यह मान लेना काफी उचित था कि कोई व्यक्ति, कहीं न कहीं, yieldएक चर के नाम के रूप में इस्तेमाल कर सकता है । लेकिन क्योंकि इसमें पहले से मौजूद परिदृश्य नहीं था<variable name> return वाक्य-रचना में सही था, yield returnभाषा में जोड़ा गया ताकि मौजूदा कोड के साथ 100% पीछे की संगतता बनाए रखते हुए जनरेटर को पेश करना संभव हो सके।

और यही कारण है कि asyncएक फ़ंक्शन संशोधक के रूप में जोड़ा गया था: मौजूदा कोड को तोड़ने से बचने के लिए जो awaitएक चर नाम के रूप में उपयोग किया जाता है। चूंकि asyncपहले से मौजूद कोई विधि नहीं है , कोई पुराना कोड अमान्य नहीं है, और नए कोड में, कंपाइलर asyncटैग की उपस्थिति का उपयोग यह जानने के लिए कर awaitसकता है कि उसे एक कीवर्ड के रूप में माना जाना चाहिए और पहचानकर्ता नहीं।


3
यह बहुत कुछ है जो इस लेख में भी कहा गया है (मूल रूप से @svick द्वारा टिप्पणियों में पोस्ट किया गया है), लेकिन किसी ने भी इसे उत्तर के रूप में पोस्ट नहीं किया। केवल ढाई साल लगे! धन्यवाद :)
ConditionRacer

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

6

यह कॉलबैक के साथ एक सामान्य विधि से एक वस्तु के लिए विधि को बदलता है जिसके लिए कोड पीढ़ी के लिए पूरी तरह से अलग दृष्टिकोण की आवश्यकता होती है

और जब ऐसा कुछ होता है, तो यह स्पष्ट रूप से सूचित करने के लिए प्रथागत है (हमने C ++ से उस पाठ को सीखा)


तो यह वास्तव में पाठक / प्रोग्रामर के लिए कुछ है, और संकलक के लिए इतना नहीं है?
सशर्त

@ जस्टिन 984 यह निश्चित रूप से संकलक को कुछ विशेष जरूरतों को इंगित करने में मदद करता है
शाफ़्ट सनकी

मुझे लगता है कि मैं उत्सुक हूं कि कंपाइलर को इसकी आवश्यकता क्यों है। क्या यह केवल विधि को पार्स नहीं कर सकता है और यह देख सकता है कि प्रतीक्षा कहीं विधि निकाय में है?
ConditionRacer

यह तब मदद करता है जब आप asyncएक ही समय में कई शेड्यूल करना चाहते हैं ताकि वे एक के बाद एक न चलाएं लेकिन समवर्ती (यदि धागे कम से कम उपलब्ध हैं)
शाफ़्ट सनकी

@ जस्टिन 984: Task<T>वास्तव में लौटने वाली प्रत्येक विधि में एक asyncविधि की विशेषताएं नहीं हैं - उदाहरण के लिए, आप बस कुछ व्यवसाय / कारखाने के तर्क के माध्यम से चल सकते हैं और फिर किसी अन्य तरीके से वापस आ सकते हैं Task<T>asyncविधियों Task<T>में हस्ताक्षर में एक वापसी प्रकार होता है, लेकिन वास्तव में एक वापस नहीं होता है Task<T>, वे सिर्फ एक वापसी करते हैं Tasyncकीवर्ड के बिना इन सभी का पता लगाने के लिए , सी # कंपाइलर को विधि के सभी प्रकार के गहन निरीक्षण करने होंगे, जो संभवत: इसे थोड़ा धीमा कर देगा, और सभी तरह की अस्पष्टताओं को जन्म देगा।
Aaronaught

4

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


मुझे नीचा दिखाने का प्रलोभन दिया जा रहा है क्योंकि पहला पैराग्राफ सही होने के साथ-साथ, व्यवधान की तुलना गलत है (मेरी जानकारी में)।
पौल

मैं उन्हें उद्देश्य के संदर्भ में कुछ हद तक अनुरूप देखता हूं लेकिन स्पष्टता के लिए इसे हटा देता हूं।
वर्ल्ड इंजीनियर

व्यवधान मेरे मन में async कोड की तुलना में घटनाओं की तरह अधिक हैं - वे एक संदर्भ स्विच का कारण बनते हैं और सामान्य कोड को फिर से शुरू होने से पहले पूरा करने के लिए चलाते हैं (और सामान्य कोड चलने से भी पूरी तरह अनजान हो सकता है), जबकि async कोड के साथ विधि हो सकती है कॉलिंग थ्रेड को फिर से शुरू करने से पहले पूरा नहीं किया है। मैं देख रहा हूँ कि आप क्या कहना चाह रहे थे कि अलग-अलग व्यवस्थाओं को हूड के तहत अलग-अलग कार्यान्वयन की आवश्यकता है, लेकिन इस बात को स्पष्ट करने के लिए मेरे साथ सिर्फ जीब नहीं हुआ। (शेष के लिए +1, btw।)
पाऊल

0

ठीक है, यहाँ मेरा इस पर लेना है।

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

वे सी मैक्रोज़ के साथ लागू करने के लिए आसान हैं, जैसा कि "प्रोटॉथ्रेड्स" के बारे में निम्नलिखित पेपर में दिखाया गया है। ( http://dunkels.com/adam/dunkels06protothreads.pdf ) इसे पढ़ें। मैं इंतजार करूँगा...

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

यह "प्रोटोथ्रेड" में वर्णित कोड के नियंत्रण के स्पष्ट प्रवाह को संशोधित किए बिना किया जाता है।

अब कल्पना करें कि आपके पास इन सभी "प्रोटोथ्रेड्स" को बदले में एक बड़ा लूप है, और आप समवर्ती रूप से एक ही थ्रेड पर "प्रोटोथ्रेड्स" निष्पादित कर रहे हैं।

इस दृष्टिकोण में दो कमियां हैं:

  1. आप पुनरारंभ के बीच स्थानीय चर में राज्य नहीं रख सकते।
  2. आप एक मनमाने कॉल गहराई से "प्रोटोथ्रेड" को निलंबित नहीं कर सकते। (सभी निलंबन बिंदु 0 स्तर पर होने चाहिए)

दोनों के लिए वर्कअराउंड हैं:

  1. सभी स्थानीय चर को प्रोटोथ्रेड के संदर्भ तक खींचा जाना चाहिए (संदर्भ जो पहले से ही इस तथ्य की आवश्यकता है कि प्रोटॉथ्रेड को अपना अगला पुनरारंभ बिंदु स्टोर करना होगा)
  2. यदि आपको लगता है कि आपको वास्तव में एक प्रोटोथ्रेड से दूसरे प्रोटोथ्रेड को कॉल करने की आवश्यकता है, तो एक बच्चे को "स्पॉन" फैलाएं और बच्चे के पूरा होने तक निलंबित करें।

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

और यह क्या asyncऔर क्या हैawait सब के बारे में कर रहे हैं: बनाने (stackless) coroutines।

C # में कोरआउट को (जेनेरिक या गैर-जेनेरिक) वर्ग की वस्तुओं के रूप में पुनरीक्षित किया जाता है Task

मुझे ये कीवर्ड बहुत भ्रामक लगते हैं। मेरी मानसिक रीडिंग है:

  • async "संदिग्ध" के रूप में
  • await "पूरा होने तक सस्पेंड"
  • Task "भविष्य ..." के रूप में

अभी। क्या हमें वास्तव में फ़ंक्शन को चिह्नित करने की आवश्यकता है async? यह कहने के अलावा कि यह फ़ंक्शन को एक coroutine बनाने के लिए कोड पुनर्लेखन तंत्र को ट्रिगर करना चाहिए, यह कुछ अस्पष्टताओं को हल करता है। इस कोड पर विचार करें।

public Task<object> AmIACoroutine() {
    var tcs = new TaskCompletionSource<object>();
    return tcs.Task;
}

यह मानते हुए कि asyncयह अनिवार्य नहीं है, क्या यह एक कोरटाइन या सामान्य कार्य है? संकलक को इसे कोरटाइन के रूप में फिर से लिखना चाहिए या नहीं? दोनों अलग-अलग अंतिम शब्दार्थों के साथ संभव हो सकते हैं।

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