एक पूर्ण कार्य पर Await कार्य के समान है।


117

मैं वर्तमान में स्टीफन क्लीरी द्वारा " कॉनएरेबिलिटी इन सी # कुकबुक " पढ़ रहा हूं , और मैंने निम्नलिखित तकनीक पर ध्यान दिया है:

var completedTask = await Task.WhenAny(downloadTask, timeoutTask);  
if (completedTask == timeoutTask)  
  return null;  
return await downloadTask;  

downloadTaskएक कॉल है httpclient.GetStringAsync, और timeoutTaskनिष्पादित कर रहा है Task.Delay

इस घटना में कि यह समय समाप्त नहीं हुआ, फिर downloadTaskपहले से ही पूरा हो गया है। वापसी के बजाय दूसरा इंतजार करना क्यों आवश्यक है downloadTask.Result, यह देखते हुए कि कार्य पहले ही पूरा हो चुका है?


3
यहां कुछ संदर्भ गायब है, और जब तक लोग आसानी से पुस्तक तक नहीं पहुंचते, आपको इसे शामिल करने की आवश्यकता है। क्या है downloadTaskऔर timeoutTask? वो क्या करते हैं?
माइक पेर्रेनौड

7
मैं यहां सफल समापन के लिए वास्तविक जांच नहीं देख रहा हूं। काम बहुत अच्छी तरह से गलती हो सकती है, और उस मामले में व्यवहार होगा (अलग हो AggregateExceptionके साथ Resultके माध्यम से बनाम पहले अपवाद ExceptionDispatchInfoके साथ await)। स्टीफन टौब के "टास्क एक्ससेप्शन हैंडलिंग इन .NET 4.5" के बारे में अधिक विस्तार से चर्चा की गई: blogs.msdn.com/b/pfxteam/archive/2011/09/28/… )
Kirill Shlenskiy

आपको इसे एक उत्तर देना चाहिए @KirillShlenskiy
Carsten

@MichaelPerrenoud आप सही हैं, ध्यान देने के लिए धन्यवाद, मैं प्रश्न संपादित करूँगा।
julio.g

जवाबों:


160

यहाँ पहले से ही कुछ अच्छे उत्तर / टिप्पणियाँ हैं, लेकिन सिर्फ झंकार करने के लिए ...

दो कारण मैं पसंद कर रहे हैं awaitसे अधिक Result(या Wait)। पहला यह है कि त्रुटि हैंडलिंग अलग है; awaitअपवाद को एक में नहीं लपेटता है AggregateException। आदर्श रूप से, अतुल्यकालिक कोड से कभी भी निपटना नहीं चाहिए AggregateException, जब तक कि यह विशेष रूप से नहीं चाहता है।

दूसरा कारण थोड़ा और सूक्ष्म है। जैसा कि मैंने अपने ब्लॉग पर (और पुस्तक में) वर्णन किया है, Result/ Waitगतिरोध पैदा कर सकता है , और एक asyncविधि में उपयोग किए जाने पर और भी अधिक सूक्ष्म गतिरोध पैदा कर सकता है । तो, जब मैं कोड के माध्यम से पढ़ रहा हूँ और मैं एक को देखने Resultया Wait, कि एक तत्काल चेतावनी झंडा है। Result/ Waitकेवल सही है अगर आप कर रहे हैं पूरी तरह से सुनिश्चित करें कि कार्य पहले ही पूरा हो गया है। न केवल यह एक नज़र में (वास्तविक-विश्व कोड में) देखना कठिन है, बल्कि कोड परिवर्तन के लिए यह अधिक भंगुर है।

यह कहने के लिए नहीं है कि Result/ कभी इस्तेमाल नहीं किया Waitजाना चाहिए । मैं अपने स्वयं के कोड में इन दिशानिर्देशों का पालन करता हूं:

  1. एक आवेदन में अतुल्यकालिक कोड केवल उपयोग कर सकते हैं await
  2. अतुल्यकालिक उपयोगिता कोड (एक पुस्तकालय में) कभी-कभी उपयोग कर सकता है Result/ Waitयदि कोड वास्तव में इसके लिए कहता है। इस तरह के उपयोग में शायद टिप्पणियां होनी चाहिए।
  3. समानांतर कार्य कोड का उपयोग कर सकते हैं Resultऔर Wait

ध्यान दें कि (1) अब तक सामान्य मामला है, इसलिए मेरी प्रवृत्ति awaitहर जगह का उपयोग करने और अन्य मामलों को सामान्य नियम के अपवाद के रूप में मानने की है।


हमने अपनी परियोजनाओं में 'प्रतीक्षा' के बजाय 'परिणाम' का उपयोग करते हुए गतिरोध का सामना किया। गड़बड़ किए गए भाग में कोई संकलन त्रुटि नहीं है और आपका कोड थोड़ी देर के बाद परतदार हो जाता है।
अहमद मौसवी

@Stephen आप मुझे समझाएंगे कि क्यों "आदर्श रूप से, अतुल्यकालिक कोड को कभी भी एग्रीगेटएक्सैप्टेशन से निपटना नहीं चाहिए, जब तक कि यह विशेष रूप से नहीं चाहता है"
vcRobe

4
@vcRobe क्योंकि आवरण को awaitरोकता है AggregateExceptionAggregateExceptionसमानांतर प्रोग्रामिंग के लिए डिज़ाइन किया गया था, अतुल्यकालिक प्रोग्रामिंग नहीं।
स्टीफन क्लीयर

2
> "प्रतीक्षा केवल सही है यदि आप पूरी तरह से सुनिश्चित हैं कि कार्य पहले से ही पूरा हो गया है।" .... फिर इसे प्रतीक्षा क्यों कहा जाता है?
रायन द लीच

4
@RyanTheLeach: डायनेमिक टास्क पैरेललिज्म इंस्टेंसेस में Waitशामिल होने का मूल उद्देश्य था । अतुल्यकालिक उदाहरणों के लिए प्रतीक्षा करने के लिए इसका उपयोग करना खतरनाक है। Microsoft ने एक नया "वादा" प्रकार शुरू करने पर विचार किया, लेकिन इसके बजाय मौजूदा का उपयोग करने के लिए चुना ; अतुल्यकालिक कार्यों के लिए मौजूदा प्रकार का पुन: उपयोग करने का व्यापार यह है कि आप कई API के साथ अंत करते हैं जिनका उपयोग केवल अतुल्यकालिक कोड में नहीं किया जाना चाहिए। TaskTaskTaskTask
स्टीफन क्लीयर

12

यह समझ में आता timeoutTaskहै Task.Delayकि क्या उत्पाद है , जो मुझे विश्वास है कि यह पुस्तक में क्या है।

Task.WhenAnyरिटर्न Task<Task>, जहां आंतरिक कार्य उन में से एक है जिन्हें आपने तर्क के रूप में पारित किया है। इसे इस तरह दोबारा लिखा जा सकता है:

Task<Task> anyTask = Task.WhenAny(downloadTask, timeoutTask);
await anyTask;
if (anyTask.Result == timeoutTask)  
  return null;  
return downloadTask.Result; 

या तो मामले में, क्योंकि downloadTaskपहले ही पूरा हो चुका है, return await downloadTaskऔर दोनों के बीच बहुत मामूली अंतर है return downloadTask.Result। यह है कि बाद में फेंक देंगे AggregateExceptionजो किसी भी मूल अपवाद को लपेटता है, जैसा कि @KirillShlenskiy ने टिप्पणी में बताया है। पूर्व केवल मूल अपवाद को फिर से फेंक देगा।

किसी भी स्थिति में, जहाँ भी आप अपवादों को संभालते हैं, आपको AggregateExceptionत्रुटि के कारण को प्राप्त करने के लिए, वैसे भी और उसके आंतरिक अपवादों की जाँच करनी चाहिए ।

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