รับสามงาน - 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
ถือกำเนิดสนับสนุนคอมไพเลอร์ที่ดีสำหรับasync
/ await
และเป็นประโยชน์เมื่อสิ่งเหล่านั้นไม่ได้อยู่ นอกจากนี้ยังมีประโยชน์เมื่อคุณมีงานตามอำเภอใจมากกว่า 3 งานที่รอบคอบ
แต่: เรายังคงมีปัญหาที่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);
}
วิธีการ "ซิงค์เส้นทางพร้อมทางเลือกสำรอง async" นี้เป็นเรื่องปกติที่พบเห็นได้ทั่วไปโดยเฉพาะอย่างยิ่งในรหัสประสิทธิภาพสูง โปรดทราบว่าจะไม่ช่วยเลยหากการดำเนินการเสร็จสิ้นจะไม่พร้อมกันอย่างแท้จริง
สิ่งเพิ่มเติมที่ใช้ที่นี่:
ด้วย C # เมื่อเร็ว ๆ นี้รูปแบบทั่วไปสำหรับasync
เมธอด fallback นั้นถูกนำไปใช้เป็นฟังก์ชันโลคัล:
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 Core สำหรับTask
และทุกที่ValueTask<T>