विभिन्न परिणामों के साथ कई कार्य की प्रतीक्षा कर रहा है


237

मेरे 3 कार्य हैं:

private async Task<Cat> FeedCat() {}
private async Task<House> SellHouse() {}
private async Task<Tesla> BuyCar() {}

मेरे कोड को जारी रखने से पहले इन सभी को चलाने की आवश्यकता है और मुझे प्रत्येक से परिणाम भी चाहिए। किसी भी परिणाम में एक दूसरे के साथ कुछ भी सामान्य नहीं है

मैं 3 कार्यों को पूरा करने और फिर परिणाम प्राप्त करने के लिए कैसे कॉल और प्रतीक्षा कर सकता हूं?


25
क्या आपके पास कोई ऑर्डर करने की आवश्यकता है? यही है, क्या आप बिल्ली को खिलाने के बाद तक घर नहीं बेचना चाहते हैं?
एरिक लिपर्ट

जवाबों:


411

आपके द्वारा उपयोग किए जाने के बाद WhenAll, आप परिणामों को व्यक्तिगत रूप से बाहर निकाल सकते हैं await:

var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();

await Task.WhenAll(catTask, houseTask, carTask);

var cat = await catTask;
var house = await houseTask;
var car = await carTask;

आप भी उपयोग कर सकते हैं Task.Result(क्योंकि आप इस बिंदु से जानते हैं कि वे सभी सफलतापूर्वक पूरा कर चुके हैं)। हालांकि, मैं उपयोग करने की सलाह देता हूं awaitक्योंकि यह स्पष्ट रूप से सही है, जबकि Resultअन्य परिदृश्यों में समस्या पैदा कर सकता है।


83
आप WhenAllइसे पूरी तरह से हटा सकते हैं ; प्रतीक्षा यह सुनिश्चित करने के लिए ध्यान रखेगी कि जब तक कार्य पूरे नहीं हो जाते, आप 3 बाद के असाइनमेंट से आगे नहीं बढ़ेंगे।
सर्वि

134
Task.WhenAll()कार्य को समानांतर मोड में चलाने की अनुमति देता है। मुझे समझ नहीं आ रहा है कि @Servy ने इसे हटाने का सुझाव क्यों दिया है। बिना WhenAllवे एक
सर्गेई जी।

87
@ समाज: कार्य तुरंत निष्पादित होने लगते हैं। जैसे, catTaskयह पहले से ही चल रहा है जब यह वापस आ गया है FeedCat। तो या तो दृष्टिकोण काम करेगा - एकमात्र सवाल यह है कि क्या आप awaitउन्हें एक समय में एक या सभी को एक साथ करना चाहते हैं। त्रुटि से निपटने का तरीका थोड़ा अलग है - यदि आप उपयोग करते हैं Task.WhenAll, तो यह awaitउन सभी को करेगा , भले ही उनमें से कोई भी जल्दी विफल हो जाए।
स्टीफन क्लीयर

23
@Sergey कॉलिंग WhenAllपर कोई प्रभाव नहीं पड़ता है जब ऑपरेशन निष्पादित करते हैं, या वे कैसे निष्पादित करते हैं। यह केवल किसी भी है संभावना प्रभावशाली कैसे परिणाम मनाया जाता है की। इस विशेष मामले में, एकमात्र अंतर यह है कि पहले दो तरीकों में से एक में त्रुटि होती है, अपवाद के रूप में इस कॉल स्टैक में पहले फेंका जा रहा है स्टीफन की तुलना में मेरी विधि में (हालांकि एक ही त्रुटि हमेशा फेंक दी जाएगी, अगर कोई हो )।
सेरी

37
@ सेरी: कुंजी यह है कि एसिंक्रोनस तरीके हमेशा "हॉट" (पहले से शुरू) कार्यों को वापस करते हैं।
स्टीफन क्लीयर

99

awaitउन सभी को शुरू करने के बाद, बस तीन कार्य अलग से।

var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();

var cat = await catTask;
var house = await houseTask;
var car = await carTask;

8
@ बरगिट्टा नहीं, यह गलत है। वे समानांतर में अपना काम करेंगे। इसे चलाने के लिए स्वतंत्र महसूस करें और अपने लिए देखें।
सर्व

5
लोग सालों बाद भी यही सवाल पूछते रहते हैं ... मुझे लगता है कि फिर से तनाव में

9
@StephenYork Task.WhenAllपरिवर्तनों को जोड़ना वस्तुतः कार्यक्रम के व्यवहार के बारे में, किसी भी अवलोकन योग्य तरीके से नहीं है। यह विशुद्ध रूप से निरर्थक विधि कॉल है। आप इसे जोड़ने के लिए स्वागत कर रहे हैं, यदि आप एक सौंदर्य पसंद के रूप में पसंद करते हैं, लेकिन यह कोड को क्या करता है यह नहीं बदलता है। कोड का निष्पादन समय उस विधि कॉल के साथ या उसके बिना समान होगा (अच्छी तरह से, तकनीकी रूप से कॉलिंग के लिए वास्तव में एक छोटा ओवरहेड होगा WhenAll, लेकिन यह नगण्य होना चाहिए), केवल उस संस्करण को इस संस्करण की तुलना में चलाने के लिए थोड़ा लंबा बनाता है ।
सर्व करें

4
@StephenYork आपका उदाहरण दो कारणों से क्रमिक रूप से संचालन करता है। आपके अतुल्यकालिक तरीके वास्तव में अतुल्यकालिक नहीं हैं, वे सिंक्रोनस हैं। तथ्य यह है कि आपके पास तुल्यकालिक विधियां हैं जो हमेशा पहले से ही पूर्ण किए गए कार्यों को वापस करते हैं, उन्हें समवर्ती रूप से चलने से रोकता है। इसके बाद, आप वास्तव में तीनों अतुल्यकालिक तरीकों को शुरू करने के इस जवाब में नहीं दिखाए जाते हैं, और फिर बारी-बारी से तीन कार्यों की प्रतीक्षा कर रहे हैं। आपका उदाहरण पिछले समाप्त होने तक प्रत्येक विधि को कॉल नहीं करता है, इस प्रकार स्पष्ट रूप से इस कोड के विपरीत, जब तक कि पिछले समाप्त नहीं हो जाता है, तब तक किसी को शुरू करने से रोका जा सकता है।
सेवित

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

37

यदि आप C # 7 का उपयोग कर रहे हैं, तो आप इस तरह से एक आसान आवरण विधि का उपयोग कर सकते हैं ...

public static class TaskEx
{
    public static async Task<(T1, T2)> WhenAll<T1, T2>(Task<T1> task1, Task<T2> task2)
    {
        return (await task1, await task2);
    }
}

... इस तरह के सुविधाजनक वाक्यविन्यास को सक्षम करने के लिए जब आप विभिन्न प्रकार के रिटर्न के साथ कई कार्यों पर इंतजार करना चाहते हैं। निश्चित रूप से प्रतीक्षा करने के लिए आपको विभिन्न कार्यों के लिए कई ओवरलोड करने होंगे।

var (someInt, someString) = await TaskEx.WhenAll(GetIntAsync(), GetStringAsync());

हालाँकि, अगर आप इस उदाहरण को किसी वास्तविक चीज़ में बदलने का इरादा रखते हैं, तो ValueTask और पहले से ही पूर्ण किए गए कार्यों के आसपास कुछ अनुकूलन के लिए मार्क ग्रेवेल का उत्तर देखें।


ट्यूपल्स यहां शामिल केवल C # 7 फीचर हैं। वे निश्चित रूप से अंतिम रिलीज में हैं।
जोएल म्यूलर

मैं tuples और c # 7 के बारे में जानता हूं। मेरा मतलब है कि मुझे वह तरीका नहीं मिल रहा है जब सभी tuples लौटाते हैं। क्या नामस्थान / पैकेज?
यूरी शेरेबाकोव

@YuryShcherbakov Task.WhenAll()टपल नहीं लौटा रहा है। एक Resultकार्य पूरा होने के बाद दिए गए कार्यों के गुणों से निर्मित किया जा रहा है Task.WhenAll()
क्रिस चारबारुक

2
मैं सुझाव दूंगा कि आप .Resultअपने उदाहरण की नकल करके अन्य लोगों को बुरे व्यवहार से बचने के लिए स्टीफन के तर्क के अनुसार कॉल करें।
जुलैलेगॉन

मुझे आश्चर्य है कि यह पद्धति इस ढांचे का हिस्सा क्यों नहीं है? यह बहुत उपयोगी लगता है। क्या वे समय से बाहर भाग गए और उन्हें एक ही रिटर्न प्रकार पर रोकना पड़ा?
इयान

14

तीन कार्यों को देखते हुए - FeedCat(), SellHouse()और BuyCar(), दो दिलचस्प मामले हैं: या तो वे सभी सिंक्रोनस को पूरा करते हैं (किसी कारण से, शायद कैशिंग या एक त्रुटि), या वे नहीं करते हैं।

मान लीजिए कि हमारे पास प्रश्न है:

Task<string> DoTheThings() {
    Task<Cat> x = FeedCat();
    Task<House> y = SellHouse();
    Task<Tesla> z = BuyCar();
    // what here?
}

अब, एक सरल तरीका होगा:

Task.WhenAll(x, y, z);

लेकिन ... जो परिणामों के प्रसंस्करण के लिए सुविधाजनक नहीं है; हम आम तौर पर चाहते हैं awaitकि:

async Task<string> DoTheThings() {
    Task<Cat> x = FeedCat();
    Task<House> y = SellHouse();
    Task<Tesla> z = BuyCar();

    await Task.WhenAll(x, y, z);
    // presumably we want to do something with the results...
    return DoWhatever(x.Result, y.Result, z.Result);
}

लेकिन यह बहुत सारे ओवरहेड करता है और विभिन्न सरणियों ( params Task[]सरणी सहित ) और सूचियों (आंतरिक रूप से) को आवंटित करता है । यह काम करता है, लेकिन यह महान IMO नहीं है। कई तरीकों से ऑपरेशन का उपयोग करना सरल होता है asyncऔर awaitबदले में प्रत्येक:

async Task<string> DoTheThings() {
    Task<Cat> x = FeedCat();
    Task<House> y = SellHouse();
    Task<Tesla> z = BuyCar();

    // do something with the results...
    return DoWhatever(await x, await y, await z);
}

ऊपर टिप्पणियों में से कुछ का उपयोग कर के विपरीत awaitके बजाय Task.WhenAllबनाता है कोई फर्क नहीं कैसे कार्य चलाने (समवर्ती, क्रमिक रूप से, आदि) के लिए। उच्चतम स्तर पर, / के लिए अच्छे संकलक समर्थन की Task.WhenAll भविष्यवाणी करता है , और उन चीजों के मौजूद नहीं होने पर उपयोगी था । यह तब भी उपयोगी होता है जब आपके पास 3 विवेकी कार्यों के बजाय कार्यों की एक मनमानी होती है।asyncawait

लेकिन: हम अभी भी समस्या है कि async/ awaitनिरंतरता के लिए संकलक शोर का एक बहुत उत्पन्न करता है। यदि यह संभावना है कि कार्य वास्तव में समकालिक रूप से पूर्ण हो सकते हैं , तो हम एक अतुल्यकालिक कमबैक के साथ एक समकालिक पथ में निर्माण करके इसे अनुकूलित कर सकते हैं:

Task<string> DoTheThings() {
    Task<Cat> x = FeedCat();
    Task<House> y = SellHouse();
    Task<Tesla> z = BuyCar();

    if(x.Status == TaskStatus.RanToCompletion &&
       y.Status == TaskStatus.RanToCompletion &&
       z.Status == TaskStatus.RanToCompletion)
        return Task.FromResult(
          DoWhatever(a.Result, b.Result, c.Result));
       // we can safely access .Result, as they are known
       // to be ran-to-completion

    return Awaited(x, y, z);
}

async Task Awaited(Task<Cat> a, Task<House> b, Task<Tesla> c) {
    return DoWhatever(await x, await y, await z);
}

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

अतिरिक्त चीजें जो यहां लागू होती हैं:

  1. हाल ही में C # के साथ, एक सामान्य पैटर्न यह है कि asyncफालबैक विधि आमतौर पर स्थानीय फ़ंक्शन के रूप में लागू की जाती है:

    Task<string> DoTheThings() {
        async Task<string> Awaited(Task<Cat> a, Task<House> b, Task<Tesla> c) {
            return DoWhatever(await a, await b, await c);
        }
        Task<Cat> x = FeedCat();
        Task<House> y = SellHouse();
        Task<Tesla> z = BuyCar();
    
        if(x.Status == TaskStatus.RanToCompletion &&
           y.Status == TaskStatus.RanToCompletion &&
           z.Status == TaskStatus.RanToCompletion)
            return Task.FromResult(
              DoWhatever(a.Result, b.Result, c.Result));
           // we can safely access .Result, as they are known
           // to be ran-to-completion
    
        return Awaited(x, y, z);
    }
  2. पसंद ValueTask<T>करें Task<T>कि क्या कई अलग-अलग रिटर्न वैल्यू के साथ पूरी तरह से सिंक्रोनाइज़ की गई चीजों का अच्छा मौका है:

    ValueTask<string> DoTheThings() {
        async ValueTask<string> Awaited(ValueTask<Cat> a, Task<House> b, Task<Tesla> c) {
            return DoWhatever(await a, await b, await c);
        }
        ValueTask<Cat> x = FeedCat();
        ValueTask<House> y = SellHouse();
        ValueTask<Tesla> z = BuyCar();
    
        if(x.IsCompletedSuccessfully &&
           y.IsCompletedSuccessfully &&
           z.IsCompletedSuccessfully)
            return new ValueTask<string>(
              DoWhatever(a.Result, b.Result, c.Result));
           // we can safely access .Result, as they are known
           // to be ran-to-completion
    
        return Awaited(x, y, z);
    }
  3. यदि संभव हो तो, पसंद IsCompletedSuccessfullyकरें Status == TaskStatus.RanToCompletion; यह अब .NET कोर Taskमें और हर जगह के लिए मौजूद हैValueTask<T>


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

@ अगर आप सही कह रहे हैं, तो यह टिप्पणी थी; मैं परिणामों का उपयोग दिखाने के लिए एक ट्वीक जोड़ देंगे
मार्क Gravell

@Servy ट्वीक जोड़ा
मार्क Gravell

इसके अलावा अगर आप शुरुआती समकालिक कार्यों को जल्दी से पूरा करने जा रहे हैं, तो आप किसी भी कार्य को समकालिक रूप से रद्द या दोषपूर्ण होने के बजाय केवल सफलतापूर्वक पूरा करने वाले को संभाल सकते हैं। यदि आपने यह निर्णय लिया है कि यह एक अनुकूलन है जिसे आपके कार्यक्रम की आवश्यकता है (जो दुर्लभ होगा, लेकिन होगा) तो आप सभी तरह से जा सकते हैं।
सर्विस

@Servy जो एक जटिल विषय है - आपको दो परिदृश्यों से अलग-अलग अपवाद शब्दार्थ मिलते हैं - एक अपवाद को ट्रिगर करने की प्रतीक्षा करना पहुँच से अलग व्यवहार करता है। अपवाद को ट्रिगर करने के लिए। उस बिंदु पर IMO हम चाहिए awaitकि अपवाद दुर्लभ लेकिन सार्थक कर रहे हैं, "बेहतर" अपवाद अर्थ विज्ञान प्राप्त करने के लिए इस धारणा पर
मार्क Gravell

12

आप उन्हें कार्यों में संग्रहीत कर सकते हैं, फिर उन सभी की प्रतीक्षा करें:

var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();

await Task.WhenAll(catTask, houseTask, carTask);

Cat cat = await catTask;
House house = await houseTask;
Car car = await carTask;

var catTask = FeedCat()फ़ंक्शन निष्पादित नहीं करता है FeedCat()और परिणाम को catTaskबनाने में संग्रहीत करता हैawait Task.WhenAll() विधि को बेकार का हिस्सा क्योंकि विधि पहले ही निष्पादित हो चुकी है ??
क्रांग प्राइम जूल

1
@sanuel यदि वे कार्य <t> वापस करते हैं, तो नहीं ... वे async ओपन शुरू करते हैं, लेकिन इसके लिए इंतजार न करें
रीड कोप्स

मुझे नहीं लगता कि यह सटीक है, कृपया स्टीफनक्लेरी के उत्तर के तहत चर्चाओं को देखें ... सर्विसी के उत्तर को भी देखें।
रोजी कासिम

1
अगर मुझे जोड़ने की जरूरत है। ConfigrtueAwait (गलत)। क्या मैं इसे केवल Task.WhenAll या प्रत्येक वेटर से जोड़ूंगा जो इस प्रकार है?
एस्ट्रोहार्प

सामान्य रूप से @AstroSharp, यह उन सभी को जोड़ने के लिए एक अच्छा विचार है (यदि पहला पूरा हो गया है, तो इसे प्रभावी रूप से नजरअंदाज कर दिया जाता है), लेकिन इस मामले में, यह संभवत: केवल पहले करना ठीक होगा - जब तक कि अधिक async न हो सामान बाद में हो रहा है।
रीड कोपसे

6

यदि आप सभी त्रुटियों को लॉग इन करने की कोशिश कर रहे हैं, तो सुनिश्चित करें कि आप अपने कोड में Task.WhenAll लाइन रखें, बहुत सारी टिप्पणियों का सुझाव है कि आप इसे हटा सकते हैं और व्यक्तिगत कार्यों की प्रतीक्षा कर सकते हैं। Task.WhenAll त्रुटि से निपटने के लिए वास्तव में महत्वपूर्ण है। इस पंक्ति के बिना आप संभावित अपवादों के लिए संभावित रूप से अपना कोड खुला छोड़ रहे हैं।

var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();

await Task.WhenAll(catTask, houseTask, carTask);

var cat = await catTask;
var house = await houseTask;
var car = await carTask;

निम्नलिखित कोड में FeedCat अपवाद की कल्पना करें:

var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();

var cat = await catTask;
var house = await houseTask;
var car = await carTask;

उस मामले में आप कभी भी घर पर इंतजार नहीं करेंगे और न ही कारटस्क पर। यहाँ 3 संभावित परिदृश्य हैं:

  1. जब तक कि FeedCat विफल नहीं हो जाता है तब SellHouse सफलतापूर्वक पूर्ण हो जाता है। इस मामले में आप ठीक हैं।

  2. SellHouse पूर्ण नहीं है और कुछ बिंदु पर अपवाद के साथ विफल रहता है। अपवाद नहीं देखा गया है और अंतिम धागे पर पुनर्विचार किया जाएगा।

  3. SellHouse पूरा नहीं हुआ है और इसके अंदर इंतजार कर रहा है। यदि ASP.NET SellHouse में आपका कोड चलता है, तो जैसे ही इसके अंदर के कुछ इंतजार पूरे होंगे, विफल हो जाएगा। ऐसा इसलिए होता है क्योंकि आपने मूल रूप से फायर किया और कॉल भूल गए और फीडबैक के विफल होते ही सिंक्रोनाइज़ेशन संदर्भ खो गया।

यहां वह त्रुटि है जो आपको केस के लिए मिलेगी (3):

System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Web.ThreadContext.AssociateWithCurrentThread(Boolean setImpersonationContext)
   at System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext)
   at System.Web.HttpApplication.System.Web.Util.ISyncContext.Enter()
   at System.Web.Util.SynchronizationHelper.SafeWrapCallback(Action action)
   at System.Threading.Tasks.Task.Execute()
   --- End of inner exception stack trace ---
---> (Inner Exception #0) System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Web.ThreadContext.AssociateWithCurrentThread(Boolean setImpersonationContext)
   at System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext)
   at System.Web.HttpApplication.System.Web.Util.ISyncContext.Enter()
   at System.Web.Util.SynchronizationHelper.SafeWrapCallback(Action action)
   at System.Threading.Tasks.Task.Execute()<---

मामले (2) के लिए आपको समान त्रुटि मिलेगी लेकिन मूल अपवाद स्टैक ट्रेस के साथ।

.NET 4.0 के लिए और बाद में आप TaskScheduler.UnobservedTaskException का उपयोग करके बिना अपवाद वाले अपवादों को पकड़ सकते हैं। .NET 4.5 के लिए और बाद में बिना अपवाद के अपवाद को .NET 4.0 के लिए डिफ़ॉल्ट रूप से निगल लिया जाता है, अपवादित अपवाद आपकी प्रक्रिया को क्रैश कर देगा।

यहाँ अधिक जानकारी: .NET 4.5 में टास्क एक्सेप्शन हैंडलिंग


2

आप Task.WhenAllवर्णित के रूप में उपयोग कर सकते हैं , या Task.WaitAll, इस पर निर्भर करता है कि आप धागा प्रतीक्षा करना चाहते हैं। दोनों के स्पष्टीकरण के लिए लिंक पर एक नज़र डालें।

WaitAll बनाम जब सभी


2

उपयोग करें Task.WhenAllऔर फिर परिणामों की प्रतीक्षा करें:

var tCat = FeedCat();
var tHouse = SellHouse();
var tCar = BuyCar();
await Task.WhenAll(tCat, tHouse, tCar);
Cat cat = await tCat;
House house = await tHouse;
Tesla car = await tCar; 
//as they have all definitely finished, you could also use Task.Value.

मिमी ... टास्क नहीं। वैल्यू (शायद यह 2013 में मौजूद था?), बल्कि tCat.Result, tHouse.Result या tCar.Result
स्टीफन यॉर्क

1

आगे की चेतावनी

बस इस और इस तरह के अन्य थ्रेड्स पर आने वाले लोगों के लिए एक त्वरित हेडअप है जो एसिंक्स + वेट + टास्क टूल-सेट का उपयोग करके एंटिटीफ्रेमवर्क को समानांतर करने का एक तरीका खोज रहा है : यहां दिखाया गया पैटर्न ध्वनि है, हालांकि, जब यह ईएफ के विशेष स्नोफ्लेक की बात आती है तो आप नहीं करेंगे समानांतर निष्पादन को तब तक प्राप्त करें जब तक कि आप प्रत्येक (प्रत्येक) Async () कॉल में एक अलग (नया) db- संदर्भ-उदाहरण का उपयोग न करें।

एफई-डीबी-संदर्भों की अंतर्निहित डिजाइन सीमाओं के कारण इस तरह की चीज आवश्यक है, जो एक ही एफई-डीबी-संदर्भ उदाहरण में समानांतर में कई प्रश्नों को चलाने से मना करती है।


पहले से दिए गए उत्तरों को भुनाना, यह सुनिश्चित करने का तरीका है कि आप इस मामले में भी सभी मान एकत्र करें कि एक या एक से अधिक कार्य एक अपवाद का परिणाम देते हैं:

  public async Task<string> Foobar() {
    async Task<string> Awaited(Task<Cat> a, Task<House> b, Task<Tesla> c) {
        return DoSomething(await a, await b, await c);
    }

    using (var carTask = BuyCarAsync())
    using (var catTask = FeedCatAsync())
    using (var houseTask = SellHouseAsync())
    {
        if (carTask.Status == TaskStatus.RanToCompletion //triple
            && catTask.Status == TaskStatus.RanToCompletion //cache
            && houseTask.Status == TaskStatus.RanToCompletion) { //hits
            return Task.FromResult(DoSomething(catTask.Result, carTask.Result, houseTask.Result)); //fast-track
        }

        cat = await catTask;
        car = await carTask;
        house = await houseTask;
        //or Task.AwaitAll(carTask, catTask, houseTask);
        //or await Task.WhenAll(carTask, catTask, houseTask);
        //it depends on how you like exception handling better

        return Awaited(catTask, carTask, houseTask);
   }
 }

एक वैकल्पिक कार्यान्वयन जिसमें कमोबेश समान प्रदर्शन विशेषताएँ हो सकती हैं:

 public async Task<string> Foobar() {
    using (var carTask = BuyCarAsync())
    using (var catTask = FeedCatAsync())
    using (var houseTask = SellHouseAsync())
    {
        cat = catTask.Status == TaskStatus.RanToCompletion ? catTask.Result : (await catTask);
        car = carTask.Status == TaskStatus.RanToCompletion ? carTask.Result : (await carTask);
        house = houseTask.Status == TaskStatus.RanToCompletion ? houseTask.Result : (await houseTask);

        return DoSomething(cat, car, house);
     }
 }

-1
var dn = await Task.WhenAll<dynamic>(FeedCat(),SellHouse(),BuyCar());

यदि आप कैट तक पहुँचना चाहते हैं, तो आप ऐसा करते हैं:

var ct = (Cat)dn[0];

यह करने के लिए बहुत सरल है और उपयोग करने के लिए बहुत उपयोगी है, एक जटिल समाधान के बाद जाने की कोई आवश्यकता नहीं है।


1
इसके साथ सिर्फ एक समस्या है: dynamicशैतान है। यह मुश्किल COM इंटरॉप और इस तरह के लिए है, और इसे किसी भी स्थिति में उपयोग नहीं किया जाना चाहिए जहां इसकी बिल्कुल आवश्यकता नहीं है। विशेष रूप से यदि आप प्रदर्शन की परवाह करते हैं। या सुरक्षा लिखें। या फिर से भरना। या डिबगिंग।
जोएल म्यूलर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.