तीन कार्यों को देखते हुए - 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 विवेकी कार्यों के बजाय कार्यों की एक मनमानी होती है।async
await
लेकिन: हम अभी भी समस्या है कि 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);
}
यह "एसिंक्स फ़ॉलबैक के साथ सिंक पथ" दृष्टिकोण विशेष रूप से उच्च प्रदर्शन कोड में आम है जहां तुल्यकालिक पूर्णता अक्सर होती है। ध्यान दें कि यह पूरा होने में कभी भी मदद नहीं करेगा अगर हमेशा पूरी तरह से अतुल्यकालिक हो।
अतिरिक्त चीजें जो यहां लागू होती हैं:
हाल ही में 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);
}
पसंद 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);
}
यदि संभव हो तो, पसंद IsCompletedSuccessfully
करें Status == TaskStatus.RanToCompletion
; यह अब .NET कोर Task
में और हर जगह के लिए मौजूद हैValueTask<T>