2013-09-23 8 views
73

क्या कोई बता सकता है कि await और ContinueWith निम्न उदाहरण में समानार्थी हैं या नहीं। मैं पहली बार टीपीएल का उपयोग करने की कोशिश कर रहा हूं और सभी दस्तावेज पढ़ रहा हूं, लेकिन अंतर को समझ नहीं पा रहा हूं।प्रतीक्षा और जारी रखने के बीच अंतर

का इंतजार:

String webText = await getWebPage(uri); 
await parseData(webText); 

ContinueWith:

Task<String> webText = new Task<String>(() => getWebPage(uri)); 
Task continue = webText.ContinueWith((task) => parseData(task.Result)); 
webText.Start(); 
continue.Wait(); 

एक विशेष परिस्थितियों में अन्य से अधिक पसंद है?

+2

यदि आपने दूसरे उदाहरण में 'प्रतीक्षा' कॉल हटा दी है तो * दो स्निपेट (अधिकतर) समकक्ष होंगे। – Servy

+1

संभावित डुप्लिकेट [क्या Async lambda के साथ जारी रखने के बराबर कीवर्ड का इंतजार कर रहा है?] (Http://stackoverflow.com/questions/8767218/is-async-await-keyword-equivalent-to-a-continuewith-lambda) –

+0

FYI: आपकी 'getWebPage' विधि दोनों कोडों में उपयोग नहीं की जा सकती है। पहले कोड में इसमें 'कार्य ' रिटर्न प्रकार होता है जबकि दूसरे में 'स्ट्रिंग' रिटर्न प्रकार होता है। तो मूल रूप से आपका कोड संकलित नहीं करता है। - अगर सटीक होना है। –

उत्तर

61

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

वे बहुत समान हैं कि वे दोनों एक निरंतरता निर्धारित करते हैं, लेकिन जैसे ही नियंत्रण प्रवाह थोड़ा जटिल हो जाता है, awaitअधिक सरल कोड की ओर जाता है। इसके अतिरिक्त, जैसा कि टिप्पणियों में सर्वो द्वारा नोट किया गया है, एक कार्य का इंतजार करने से कुल अपवाद "अनचाहे" हो जाएंगे जो आम तौर पर सरल त्रुटि प्रबंधन की ओर ले जाता है। await का भी उपयोग करके कॉलिंग संदर्भ में निरंतरता निर्धारित होगी (जब तक आप ConfigureAwait का उपयोग नहीं करते)। ऐसा कुछ भी नहीं है जिसे "मैन्युअल रूप से" नहीं किया जा सकता है, लेकिन await के साथ ऐसा करना बहुत आसान है।

मेरा सुझाव है कि आप await और Task.ContinueWith दोनों के साथ संचालन के थोड़ा बड़े अनुक्रम को लागू करने का प्रयास करें - यह वास्तविक आंख खोलने वाला हो सकता है।

+0

दो स्निपेट के बीच त्रुटि प्रबंधन भी अलग है; उस संबंध में 'जारी रखें' पर 'प्रतीक्षा' के साथ काम करना आम तौर पर आसान है। – Servy

+0

@ सर्वी: सच है, उसके आस-पास कुछ जोड़ देगा। –

+1

शेड्यूलिंग भी काफी अलग है, यानी, संदर्भ 'parseData' किस निष्पादन में निष्पादित करता है। –

61

यहां हाल ही में कोड स्निपेट का अनुक्रम है जिसे मैंने हाल ही में एसिंक सॉल्व का उपयोग करके अंतर और विभिन्न समस्याओं को चित्रित करने के लिए उपयोग किया था।

मान लें कि आपके पास अपने जीयूआई-आधारित एप्लिकेशन में कुछ ईवेंट हैंडलर है जो बहुत समय लेता है, और इसलिए आप इसे अतुल्यकालिक बनाना चाहते हैं।

while (true) { 
    string result = LoadNextItem().Result; 
    if (result.Contains("target")) { 
     Counter.Value = result.Length; 
     break; 
    } 
} 

LoadNextItem रिटर्न एक टास्क, है कि अंततः कुछ परिणाम आप का निरीक्षण करना चाहते हैं का उत्पादन करेगा: यहाँ तुल्यकालिक तर्क आप के साथ शुरू है। यदि वर्तमान परिणाम वह है जिसे आप ढूंढ रहे हैं, तो आप UI पर कुछ काउंटर के मान को अपडेट करते हैं, और विधि से वापस आते हैं। अन्यथा, आप LoadNextItem से अधिक आइटम प्रोसेस करना जारी रखते हैं।

असीमित संस्करण के लिए पहला विचार: केवल निरंतरता का उपयोग करें! और चलो समय के लिए लूपिंग भाग को अनदेखा करते हैं। मेरा मतलब है, क्या संभवतः गलत हो सकता है?

return LoadNextItem().ContinueWith(t => { 
    string result = t.Result; 
    if (result.Contains("target")) { 
     Counter.Value = result.Length; 
    } 
}); 

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

return LoadNextItem().ContinueWith(t => { 
    string result = t.Result; 
    if (result.Contains("target")) { 
     Counter.Value = result.Length; 
    } 
}, 
TaskScheduler.FromCurrentSynchronizationContext()); 

बढ़िया है, अब हम एक विधि है कि दुर्घटना नहीं करता है! यह बदले में चुपचाप विफल रहता है। निरंतरता अलग-अलग कार्य हैं, उनकी स्थिति पूर्ववर्ती कार्य से बंधी नहीं है। तो अगर लोडNextItem दोष भी हो, तो कॉलर केवल एक कार्य देखेगा जो सफलतापूर्वक पूरा हो गया है।ठीक है, तो बस अपवाद पर जाएं, यदि कोई है:

return LoadNextItem().ContinueWith(t => { 
    if (t.Exception != null) { 
     throw t.Exception.InnerException; 
    } 
    string result = t.Result; 
    if (result.Contains("target")) { 
     Counter.Value = result.Length; 
    } 
}, 
TaskScheduler.FromCurrentSynchronizationContext()); 

ग्रेट, अब यह वास्तव में काम करता है। एक आइटम के लिए। अब, उस लूपिंग के बारे में कैसे। पता चला है, मूल तुल्यकालिक संस्करण के तर्क के लिए एक समाधान बराबर कुछ इस तरह दिखेगा:

async Task AsyncLoop() { 
    while (true) { 
     string result = await LoadNextItem(); 
     if (result.Contains("target")) { 
      Counter.Value = result.Length; 
      break; 
     } 
    } 
} 
: ऊपर के सभी के बजाय

Task AsyncLoop() { 
    return AsyncLoopTask().ContinueWith(t => 
     Counter.Value = t.Result, 
     TaskScheduler.FromCurrentSynchronizationContext()); 
} 
Task<int> AsyncLoopTask() { 
    var tcs = new TaskCompletionSource<int>(); 
    DoIteration(tcs); 
    return tcs.Task; 
} 
void DoIteration(TaskCompletionSource<int> tcs) { 
    LoadNextItem().ContinueWith(t => { 
     if (t.Exception != null) { 
      tcs.TrySetException(t.Exception.InnerException); 
     } else if (t.Result.Contains("target")) { 
      tcs.TrySetResult(t.Result.Length); 
     } else { 
      DoIteration(tcs); 
     }}); 
} 

या, आप एक ही बात करने के लिए उपयोग कर सकते हैं async

यह अब बहुत अच्छा है, है ना?

+0

धन्यवाद, वास्तव में अच्छा स्पष्टीकरण –

+0

यह एक महान उदाहरण है –

+0

यह अभी भी यूआई को अद्यतन करता है। http://pastebin.com/Y8NddKp5 – MonsterMMORPG

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