यहां हाल ही में कोड स्निपेट का अनुक्रम है जिसे मैंने हाल ही में एसिंक सॉल्व का उपयोग करके अंतर और विभिन्न समस्याओं को चित्रित करने के लिए उपयोग किया था।
मान लें कि आपके पास अपने जीयूआई-आधारित एप्लिकेशन में कुछ ईवेंट हैंडलर है जो बहुत समय लेता है, और इसलिए आप इसे अतुल्यकालिक बनाना चाहते हैं।
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
यह अब बहुत अच्छा है, है ना?
यदि आपने दूसरे उदाहरण में 'प्रतीक्षा' कॉल हटा दी है तो * दो स्निपेट (अधिकतर) समकक्ष होंगे। – Servy
संभावित डुप्लिकेट [क्या Async lambda के साथ जारी रखने के बराबर कीवर्ड का इंतजार कर रहा है?] (Http://stackoverflow.com/questions/8767218/is-async-await-keyword-equivalent-to-a-continuewith-lambda) –
FYI: आपकी 'getWebPage' विधि दोनों कोडों में उपयोग नहीं की जा सकती है। पहले कोड में इसमें 'कार्य' रिटर्न प्रकार होता है जबकि दूसरे में 'स्ट्रिंग' रिटर्न प्रकार होता है। तो मूल रूप से आपका कोड संकलित नहीं करता है। - अगर सटीक होना है। –