आप कभी भी एक विधि का 'इंतजार' क्यों करेंगे, और फिर तुरंत इसके वापसी मूल्य पर पूछताछ करेंगे?


24

में इस MSDN लेख , निम्न उदाहरण कोड प्रदान की जाती है (थोड़ा संक्षिप्तता के लिए संपादित):

public async Task<ActionResult> Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    Department department = await db.Departments.FindAsync(id);

    if (department == null)
    {
        return HttpNotFound();
    }

    return View(department);
}

FindAsyncविधि एक को पुन: प्राप्त Departmentअपने आईडी के आधार पर वस्तु, और एक रिटर्न Task<Department>। फिर विभाग को यह देखने के लिए तुरंत चेक किया जाता है कि क्या यह अशक्त है। जैसा कि मैं इसे समझता हूं, इस तरह से टास्क के मूल्य के लिए पूछना कोड निष्पादन को रोक देगा जब तक कि प्रतीक्षित विधि से मूल्य वापस नहीं आता है, प्रभावी ढंग से इसे एक तुल्यकालिक कॉल बनाता है।

आप ऐसा कभी क्यों करेंगे? Find(id)यदि आप तुरंत किसी भी तरह से ब्लॉक करने जा रहे हैं, तो क्या केवल तुल्यकालिक विधि को कॉल करना आसान नहीं होगा ?


यह कार्यान्वयन संबंधित हो सकता है। ... else return null;फिर आपको यह जांचना होगा कि विधि वास्तव में आपके द्वारा मांगे गए विभाग को मिली है या नहीं।
जेरेमी काटो

मैं किसी भी asp.net में नहीं देखता हूं, लेकिन एक डेस्टॉप ऐप में, इस तरह से आप ui को फ्रीज नहीं कर रहे हैं
Rémi

यहाँ एक लिंक दिया गया है जो डिज़ाइनर की प्रतीक्षा की अवधारणा को समझाता है ... msdn.microsoft.com/en-us/magazine/hh456401.aspx
जॉन

प्रतीक्षा केवल ASP.NET के बारे में सोचने योग्य है यदि थ्रेड संपर्क स्विच आपको धीमा कर रहे हैं, या मेमोरी उपयोग फॉर्म कई थ्रेड स्टैक आपके लिए एक समस्या है।
इयान

जवाबों:


24

जैसा कि मैं इसे समझता हूं, इस तरह से टास्क के मूल्य के लिए पूछना कोड निष्पादन को रोक देगा जब तक कि प्रतीक्षित विधि से मूल्य वापस नहीं आता है, प्रभावी ढंग से इसे एक तुल्यकालिक कॉल बनाता है।

काफी नहीं।

जब आप कॉल await db.Departments.FindAsync(id)करते हैं तो कार्य बंद कर दिया जाता है और वर्तमान थ्रेड को अन्य कार्यों द्वारा उपयोग के लिए पूल में लौटा दिया जाता है। निष्पादन का प्रवाह अवरुद्ध है (जैसा कि इसके departmentसही उपयोग के बाद भी होगा, अगर मैं चीजों को सही तरीके से समझता हूं), लेकिन थ्रेड को अन्य चीजों द्वारा उपयोग किए जाने के लिए स्वतंत्र है, जबकि आप ऑपरेशन के पूरा होने की प्रतीक्षा करते हैं (मशीन एक घटना या पूर्ण बंदरगाह द्वारा संकेत दिया गया)।

यदि आप कहते हैं d.Departments.Find(id)तो धागा वहां बैठ जाता है और प्रतिक्रिया के लिए प्रतीक्षा करता है, भले ही अधिकांश प्रसंस्करण डीबी पर किया जा रहा हो।

डिस्क बाउंड होने पर आप CPU संसाधनों को प्रभावी रूप से मुक्त कर रहे हैं।


2
लेकिन मुझे लगता है कि सभी awaitने एक ही धागे पर एक निरंतरता के रूप में शेष विधि पर हस्ताक्षर किया था (कुछ अपवाद हैं; कुछ async विधियां अपने स्वयं के धागे को स्पिन करती हैं), या asyncउसी धागे पर एक निरंतरता के रूप में विधि पर हस्ताक्षर करें ; निष्पादित करने के लिए शेष कोड (जैसा कि आप देख सकते हैं, मैं क्रिस्टल पर स्पष्ट नहीं हूं कि कैसे asyncकाम करता है)। आप जो वर्णन कर रहे हैं वह अधिक परिष्कृत रूप की तरह लगता हैThread.Sleep(untilReturnValueAvailable)
रॉबर्ट हार्वे

1
@RobertHarvey - यह इसे एक निरंतरता के रूप में निर्दिष्ट करता है, लेकिन एक बार जब आप कार्य (और इसकी निरंतरता) को संसाधित करने के लिए भेज देते हैं, तो चलाने के लिए कुछ भी नहीं बचता है। जब तक आप इसे निर्दिष्ट न करें ( ConfigureAwaitiirc के माध्यम से ) यह एक ही धागे पर होने की गारंटी नहीं है ।
तेलस्टिन

1
मेरा जवाब देखें ... निरंतरता डिफ़ॉल्ट रूप से मूल थ्रेड पर वापस भेज दी जाती है।
माइकल ब्राउन

2
मुझे लगता है कि मैं देख रहा हूं कि मैं यहां क्या याद कर रहा हूं। इसके लिए कोई भी लाभ प्रदान करने के लिए, ASP.NET MVC ढांचे को awaitइसकी कॉल करनी चाहिए public async Task<ActionResult> Details(int? id)। अन्यथा, मूल कॉल बस ब्लॉक कर देगी, department == nullसमाधान के लिए इंतजार कर रही है ।
रॉबर्ट हार्वे

2
@RobertHarvey जब तक await ..."रिटर्न" FindAsyncकॉल समाप्त हो गया। वही इंतजार करता है। इसे वेटिट कहा जाता है क्योंकि यह आपके कोड को चीजों की प्रतीक्षा करता है। (लेकिन ध्यान दें कि वर्तमान थ्रेड को चीजों के लिए इंतजार करने के समान नहीं है)
user253751

17

मैं वास्तव में नफरत करता हूं कि कोई भी उदाहरण नहीं दिखाता है कि कार्य की प्रतीक्षा करने से पहले कुछ पंक्तियों का इंतजार करना कैसे संभव है। इस पर विचार करो।

Foo foo = await getFoo();
Bar bar = await getBar();

Console.WriteLine(“Do some other stuff to prepare.”);

doStuff(foo, bar);

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

Task<Foo> foo = getFoo();
Task<Bar> bar = getBar();

Console.WriteLine(“Do some other stuff to prepare.”);

doStuff(await foo, await bar);

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


1
हम्म, यह कोर / थ्रेड्स के बारे में कम है और एसिंक्रोनस कॉल का ठीक से उपयोग करने के बारे में अधिक है।
डेडुप्लिकेटर

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

मेरा सुझाव है कि आप एक अन्य विधि कॉल के अंदर प्रतीक्षा करने के साथ सावधान रहें। कभी-कभी कंपाइलर इस प्रतीक्षा को गलत समझते हैं और आपको वास्तव में अजीब अपवाद मिलता है। सभी async / इंतजार के बाद बस सिंटैक्स चीनी है, आप शार्पलैब के साथ जांच सकते हैं कि उत्पन्न कोड कैसा दिखता है। मैंने इसे कई मौकों पर देखा और अब मुझे कॉल के ऊपर एक लाइन का इंतजार है जहां परिणाम की आवश्यकता है ... उन सिरदर्द की आवश्यकता नहीं है।
बेदखल

"इसमें थोड़ी समझदारी है।" - इसमें बहुत सारी समझदारी है। जिन मामलों में "अन्य चीजें करते रहना" लागू होता है, वे समान तरीके से लागू नहीं होते हैं; यह कहीं अधिक आम है कि आप बस चाहते हैं awaitऔर धागे को इसके बजाय पूरी तरह से अलग चीजें करने दें।
सेबेस्टियन रेडल

जब मैंने कहा "इस में थोड़ी समझदारी है" @SebastianRedl, मेरा मतलब था कि जहाँ आप स्पष्ट रूप से रन, वेट, रन, वेट के बजाय समानांतर में दोनों कार्यों को चला सकते हैं। यह जितना आप सोचते हैं उससे कहीं अधिक सामान्य है। यदि आपने अपने कोड आधार के आसपास आपको अवसर मिलेंगे तो मुझे शर्त लगाई है।
रबरडक

6

तो यहाँ पर्दे के पीछे और भी बहुत कुछ होता है। Async / Await वाक्यात्मक चीनी है। पहले FindAsync फ़ंक्शन के हस्ताक्षर को देखें। यह एक कार्य देता है। पहले से ही आप कीवर्ड का जादू देख रहे हैं, यह टास्क को एक विभाग में अनबॉक्स करता है।

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

बेशक वहाँ अधिक है जो पर्दे के पीछे होता है क्योंकि ऑपरेशन को मूल थ्रेड पर वापस भेज दिया जाता है (इसलिए अब आपको बैकग्राउंड ऑपरेशन करते समय UI के साथ सिंक्रनाइज़ करने के बारे में चिंता करने की ज़रूरत नहीं है) और कॉलिंग फ़ंक्शन के मामले में Async ( और कहा जा रहा है अतुल्यकालिक) एक ही बात ढेर हो जाता है।

तो क्या होता है कि आप नुकसान के बिना, Async संचालन का जादू प्राप्त करते हैं।


1

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


नहीं, कोई अवरोध नहीं है। यह तब तक कभी भी विभाग == नल तक नहीं पहुंचेगा, जब तक कि एसिंक्स्ट विधि पहले से ही समाप्त न हो जाए।
स्टीव

1
async awaitआम तौर पर नए धागे नहीं बनाते हैं, और अगर ऐसा किया भी है, तो आपको अभी भी यह पता लगाने के लिए उस विभाग मूल्य की प्रतीक्षा करने की आवश्यकता है कि क्या यह अशक्त है।
रॉबर्ट हार्वे

2
तो मूल रूप से आप जो कह रहे हैं, इसके लिए किसी भी तरह का फायदा public async Task<ActionResult> होना चाहिएawait
रॉबर्ट हार्वे

2
@RobertHarvey हाँ, आपको यह विचार मिल गया है। Async / Await अनिवार्य रूप से वायरल है। यदि आप एक फ़ंक्शन का "इंतजार" करते हैं, तो आपको कॉल करने वाले किसी भी फ़ंक्शन का भी इंतजार करना चाहिए। या के awaitसाथ मिश्रित नहीं किया जाना चाहिए , क्योंकि यह गतिरोध पैदा कर सकता है। Async / प्रतीक्षित श्रृंखला आम तौर पर एक हस्ताक्षर के साथ एक फ़ंक्शन पर समाप्त होती है , जिसका उपयोग ज्यादातर इवेंट हैंडलर के लिए किया जाता है, या यूआई तत्वों द्वारा सीधे किए गए फ़ंक्शन के लिए। .Wait().Resultasync void
KChaloux

1
@Steve - " ... तो यह अपने स्वयं के धागे पर होगा। " नहीं, पढ़िए टास्क अभी भी थ्रेड नहीं हैं और async समानांतर नहीं है । इसमें वास्तविक आउटपुट दर्शाया गया है कि एक नया धागा नहीं बनाया गया है।
टूलमेकरसैट

1

मैं एक अनुबंध की तरह "async" के बारे में सोचना पसंद करता हूं, एक अनुबंध जो कहता है "मैं इस अतुल्यकालिक रूप से निष्पादित कर सकता हूं यदि आपको इसकी आवश्यकता है, लेकिन आप मुझे किसी अन्य तुल्यकालिक फ़ंक्शन की तरह भी कॉल कर सकते हैं"।

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

Task<Department> deptTask = db.Departments.FindAsync(id);

और, बाद में, 10 पंक्तियों को आपके द्वारा कॉल किए जाने वाले फ़ंक्शन के नीचे

Department d = await deptTask;

इसलिए इसे एक अतुल्यकालिक फ़ंक्शन के रूप में माना जाता है।

यह आप पर निर्भर करता है।


1
यह अधिक है जैसे "मैं संदेश को अतुल्यकालिक रूप से संभालने का अधिकार सुरक्षित रखता हूं, परिणाम प्राप्त करने के लिए इसका उपयोग करें"।
Deduplicator 12

-1

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


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