वेट और कंटिन्यू के बीच का अंतर


119

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

प्रतीक्षा करें :

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

जारी रखें :

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

क्या किसी एक को विशेष परिस्थितियों में पसंद किया जाता है?


3
यदि आपने Waitदूसरे उदाहरण में कॉल को हटा दिया है तो दो स्निपेट (अधिकतर) समकक्ष होंगे।
सेवई


FYI करें: आपका getWebPageतरीका दोनों कोड में उपयोग नहीं किया जा सकता है। पहले कोड में इसका Task<string>रिटर्न टाइप होता है जबकि दूसरे में stringरिटर्न टाइप होता है। इसलिए मूल रूप से आपका कोड संकलित नहीं होता है। - अगर सटीक होना है।
रॉय नमिर

जवाबों:


101

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

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

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


2
दो स्निपेट्स के बीच त्रुटि से निपटने में भी भिन्नता है; यह आम तौर पर काम करने के लिए आसान के साथ है awaitसे अधिक ContinueWithइस संबंध में।
सेवी

@ सर्वे: सच, इसके आसपास कुछ जोड़ देगा।
जॉन स्कीट

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

जब आप कहते हैं कि प्रतीक्षारत का उपयोग कॉलिंग के संदर्भ में निरंतरता को निर्धारित करेगा , तो क्या आप इसका लाभ बता सकते हैं और दूसरी स्थिति में क्या होता है?
हैरिसन

4
@Harrison: कल्पना कीजिए कि आप एक WinForms ऐप लिख रहे हैं - यदि आप एक async विधि लिखते हैं, तो डिफ़ॉल्ट रूप से विधि के भीतर सभी कोड UI थ्रेड में चलेंगे, क्योंकि निरंतरता वहाँ निर्धारित की जाएगी। यदि आप यह निर्दिष्ट नहीं करते हैं कि आप कहां चलना चाहते हैं, तो मुझे नहीं पता कि डिफ़ॉल्ट क्या है, लेकिन यह आसानी से एक थ्रेड पूल थ्रेड पर चल सकता है ... जिस बिंदु पर आप UI का उपयोग नहीं कर सकते हैं, आदि। ।
जॉन स्कीट

100

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

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

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());

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

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());

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

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 का उपयोग कर सकते हैं:

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

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


धन्यवाद, वास्तव में अच्छी व्याख्या
एल्गर मेन्सोनिड्स

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