แนวทางปฏิบัติที่ดีที่สุดในการเขียนโปรแกรมแบบอะซิงโครนัส. Net

การเขียนโปรแกรมแบบอะซิงโครนัสช่วยให้คุณสามารถดำเนินการ I / O ที่ใช้ทรัพยากรสูงได้โดยไม่ต้องปิดกั้นบนเธรดหลักหรือเธรดการดำเนินการของแอ็พพลิเคชัน แม้ว่าจะมีประโยชน์และดูเหมือนจะใช้งานง่าย แต่ก็มีความซับซ้อนและความเสี่ยงมากมาย ความเสี่ยงที่อาจเกิดขึ้นจากการเขียนโปรแกรมแบบอะซิงโครนัสโดยเฉพาะอย่างยิ่งการใช้การเขียนโปรแกรมแบบอะซิงโครนัสในทางที่ผิดโดยไม่ปฏิบัติตามแนวทางปฏิบัติที่แนะนำรวมถึงการชะงักงันกระบวนการขัดข้องและแม้กระทั่งประสิทธิภาพที่ช้า นอกจากนี้คุณควรมีความเชี่ยวชาญในการเขียนการดีบักโค้ด async

หลีกเลี่ยงการมีประเภทผลตอบแทนเป็นโมฆะในวิธี async

เมธอดใน C # ถูกสร้างขึ้นเป็นเมธอดแบบอะซิงโครนัสโดยใช้คีย์เวิร์ด async ในลายเซ็นของเมธอด คุณสามารถมีหนึ่งหรือหลายคำที่รอคอยคำหลักภายในวิธีการ async คีย์เวิร์ด await ใช้เพื่อแสดงจุดระงับ วิธีการ async ใน C # สามารถมีผลตอบแทนประเภทใดประเภทหนึ่งดังต่อไปนี้: Task, Task และ void คีย์เวิร์ด "await" ถูกใช้ในเมธอด async เพื่อแจ้งคอมไพลเลอร์ว่าเมธอดสามารถมีจุดระงับและจุดเริ่มต้นใหม่ได้

โปรดทราบว่าเมื่อใช้ TPL สิ่งที่เทียบเท่ากับการคืนค่าโมฆะใน TPL คือ async Task คุณควรทราบว่า async void เป็นและควรใช้สำหรับเหตุการณ์ async เท่านั้น หากคุณใช้ที่อื่นคุณจะพบข้อผิดพลาด กล่าวอีกนัยหนึ่งไม่แนะนำให้ใช้วิธี async ที่มีโมฆะเป็นประเภทการส่งคืน เนื่องจากเมธอด async ที่ส่งคืนโมฆะมีความหมายที่แตกต่างกันเมื่อคุณทำงานกับข้อยกเว้นในแอปพลิเคชันของคุณ

เมื่อมีข้อยกเว้นเกิดขึ้นในเมธอด async ที่มีประเภทการส่งคืนงานหรืองานวัตถุข้อยกเว้นจะถูกเก็บไว้ในวัตถุงาน ในทางตรงกันข้ามหากคุณมีเมธอด async ที่มีประเภทการส่งคืนของโมฆะจะไม่มีวัตถุงานที่เกี่ยวข้อง ข้อยกเว้นดังกล่าวถูกยกขึ้นบน SynchronizationContext ที่แอ็คทีฟในเวลาที่เรียกเมธอดอะซิงโครนัส กล่าวอีกนัยหนึ่งคุณไม่สามารถจัดการกับข้อยกเว้นที่เกิดขึ้นภายในเมธอด async void โดยใช้ตัวจัดการข้อยกเว้นที่เขียนภายในวิธีการอะซิงโครนัส วิธีการ Async ที่มีประเภทการส่งคืนของโมฆะนั้นยากที่จะทดสอบเนื่องจากความแตกต่างนี้ในข้อผิดพลาดในการจัดการความหมาย สำหรับข้อมูลของคุณคลาส SynchronizationContext ใน System.Threading namespace แสดงบริบทการซิงโครไนซ์ใน. Net และช่วยให้คุณจัดคิวงานไปยังบริบทอื่น

รายการรหัสต่อไปนี้แสดงให้เห็นถึงสิ่งนี้ คุณมีสองวิธีคือ Test และ TestAsync และวิธีหลังจะแสดงข้อยกเว้น

public class AsyncDemo

   {

       public void Test()

       {

           try

           {

               TestAsync();

           }

           catch (Exception ex)

           {

               Console.WriteLine(ex.Message);

           }

       }

       private async void TestAsync()

       {

           throw new Exception("This is an error message");

       }

   }

นี่คือวิธีที่คุณสามารถสร้างอินสแตนซ์ของคลาส AsyncDemo และเรียกใช้วิธีการทดสอบ

static void Main(string[] args)

       {

           AsyncDemo obj = new AsyncDemo();

           obj.Test();

           Console.Read();

       }

วิธีการทดสอบทำการเรียกไปยังเมธอด TestAsync และการโทรถูกห่อหุ้มไว้ในบล็อก try-catch โดยมีจุดประสงค์เพื่อจัดการกับข้อยกเว้นที่เกิดขึ้นภายในเมธอด TestAsync อย่างไรก็ตามข้อยกเว้นที่เกิดขึ้นในเมธอด TestAsync จะไม่ถูกจับได้นั่นคือจัดการภายในการทดสอบวิธีการโทร

หลีกเลี่ยงการผสมรหัสอะซิงโครนัสและซิงโครนัส

คุณไม่ควรมีรหัสซิงโครนัสและอะซิงโครนัสผสมกัน เป็นการเขียนโปรแกรมที่ไม่ถูกต้องในการบล็อกโค้ด async โดยการโทรไปที่ Task Wait หรือ Task.Result ฉันขอแนะนำให้ใช้รหัส async ตั้งแต่ต้นจนจบ - เป็นวิธีที่ปลอดภัยที่สุดในการหลีกเลี่ยงข้อผิดพลาดจากการคืบคลานเข้ามา

คุณสามารถหลีกเลี่ยงการหยุดชะงักได้โดยใช้ ConfigureAwait(continueOnCapturedContext: false)เมื่อใดก็ตามที่คุณโทรเพื่อรอ หากคุณไม่ใช้สิ่งนี้วิธีการ async จะบล็อก ณ จุดที่มีการเรียกรอ ในกรณีนี้คุณเพียงแค่แจ้งให้ผู้รอทราบว่าอย่าจับบริบทปัจจุบัน ฉันจะบอกว่ามันเป็นแนวปฏิบัติที่ดีในการใช้. ConfigureAwait (false) เว้นแต่คุณจะมีเหตุผลเฉพาะที่จะไม่ใช้มัน

ฉันจะพูดคุยเพิ่มเติมเกี่ยวกับการเขียนโปรแกรมแบบอะซิงโครนัสในบล็อกโพสต์ในอนาคตของฉันที่นี่ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับแนวทางปฏิบัติที่ดีที่สุดในการเขียนโปรแกรมแบบอะซิงโครนัสคุณสามารถดูบทความที่ยอดเยี่ยมของ Stephen Cleary ได้ที่ MSDN