การเขียนโปรแกรมแบบอะซิงโครนัส "เติบโต" ผ่านฐานรหัส จะได้รับเมื่อเทียบกับไวรัสผีดิบ ทางออกที่ดีที่สุดคือให้มันเติบโต แต่บางครั้งก็เป็นไปไม่ได้
ฉันได้เขียนบางชนิดในไลบรารี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วิธีการใช้งานโดยไม่ต้องawaitConfigureAwait
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 ที่นี่