การเขียนโปรแกรมแบบอะซิงโครนัส "เติบโต" ผ่านฐานรหัส จะได้รับเมื่อเทียบกับไวรัสผีดิบ ทางออกที่ดีที่สุดคือให้มันเติบโต แต่บางครั้งก็เป็นไปไม่ได้
ฉันได้เขียนบางชนิดในไลบรารีNito.AsyncExของฉันเพื่อจัดการกับฐานรหัสแบบอะซิงโครนัสบางส่วน ไม่มีวิธีแก้ปัญหาที่สามารถใช้ได้ในทุกสถานการณ์
โซลูชัน A
หากคุณมีวิธีการแบบอะซิงโครนัสอย่างง่ายที่ไม่จำเป็นต้องซิงโครไนซ์กลับไปที่บริบทของมันคุณสามารถใช้Task.WaitAndUnwrapException
:
var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();
คุณไม่ต้องการใช้Task.Wait
หรือTask.Result
เพราะมันห่อข้อยกเว้นAggregateException
ไว้
โซลูชันนี้เหมาะสมถ้าMyAsyncMethod
ไม่ซิงโครไนซ์กลับไปที่บริบท ในคำอื่น ๆ ทุกawait
ในควรจะจบลงด้วยการMyAsyncMethod
ConfigureAwait(false)
หมายความว่าไม่สามารถอัปเดตองค์ประกอบ UI หรือเข้าถึงบริบทคำขอ ASP.NET
โซลูชัน B
หากMyAsyncMethod
ไม่จำเป็นต้องซิงโครไนซ์กลับไปที่บริบทของมันคุณอาจจะสามารถใช้AsyncContext.RunTask
เพื่อให้บริบทที่ซ้อนกัน:
var result = AsyncContext.RunTask(MyAsyncMethod).Result;
* อัปเดต 4/14/2014: ในไลบรารีเวอร์ชันล่าสุด API จะเป็นดังนี้:
var result = AsyncContext.Run(MyAsyncMethod);
(มันก็โอเคที่จะใช้Task.Result
ในตัวอย่างนี้เพราะRunTask
จะเผยแพร่Task
ข้อยกเว้น)
เหตุผลที่คุณอาจต้องการAsyncContext.RunTask
แทนที่จะTask.WaitAndUnwrapException
เป็นเพราะความเป็นไปได้ของการหยุดชะงักที่ค่อนข้างละเอียดอ่อนที่เกิดขึ้นใน WinForms / WPF / SL / ASP.NET:
- วิธีการแบบซิงโครนัสเรียกวิธีการแบบอะซิงโครนั
Task
ส
Task
วิธีการซิงโครไม่รอการปิดกั้นบน
async
วิธีการใช้งานโดยไม่ต้องawait
ConfigureAwait
Task
ไม่สามารถดำเนินการในสถานการณ์เช่นนี้เพราะเพียงเสร็จสมบูรณ์เมื่อasync
วิธีการเสร็จสิ้น; async
วิธีการไม่สามารถดำเนินการเพราะมันเป็นความพยายามที่จะกำหนดเวลาต่อเนื่องไปยังSynchronizationContext
และ WinForms / WPF / SL / ASP.NET จะไม่ยอมให้ความต่อเนื่องในการทำงานเพราะวิธีการซิงโครทำงานอยู่แล้วในบริบทที่
นี่คือเหตุผลหนึ่งว่าทำไมจึงควรใช้ConfigureAwait(false)
ภายในทุกasync
วิธีให้มากที่สุด
โซลูชัน C
AsyncContext.RunTask
จะไม่ทำงานในทุกสถานการณ์ ตัวอย่างเช่นหากasync
วิธีการรอสิ่งที่ต้องการให้เหตุการณ์ UI เสร็จสมบูรณ์คุณจะหยุดชะงักแม้จะอยู่ในบริบทที่ซ้อนกัน ในกรณีนั้นคุณสามารถเริ่มasync
วิธีการในกลุ่มเธรด:
var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();
อย่างไรก็ตามโซลูชันนี้ต้องการ a MyAsyncMethod
ที่จะทำงานในบริบทเธรดพูล ดังนั้นจึงไม่สามารถอัปเดตองค์ประกอบ UI หรือเข้าถึงบริบทคำขอ ASP.NET และในกรณีที่คุณได้เป็นอย่างดีอาจจะเพิ่มConfigureAwait(false)
การของawait
งบและใช้วิธีการแก้ปัญหาเอ
ปรับปรุง 2019/05/01:ปัจจุบัน "น้อยที่เลวร้ายที่สุดการปฏิบัติ" อยู่ในบทความ MSDN ที่นี่