ดังที่คุณค้นพบใน VS11 คอมไพเลอร์จะไม่อนุญาตให้ใช้async Main
เมธอด สิ่งนี้ได้รับอนุญาต (แต่ไม่เคยแนะนำ) ใน VS2010 ด้วย Async CTP
ฉันมีบล็อกโพสต์ล่าสุดเกี่ยวกับasync / คอยและโปรแกรมคอนโซลแบบอะซิงโครนัสโดยเฉพาะ นี่คือข้อมูลพื้นหลังบางส่วนจากโพสต์แนะนำ:
หาก "คอย" เห็นว่าการรอคอยยังไม่เสร็จสมบูรณ์ มันบอกให้รอที่จะเรียกใช้ส่วนที่เหลือของวิธีการเมื่อมันเสร็จสมบูรณ์แล้วส่งกลับจากวิธีการ async รอยังจะจับบริบทปัจจุบันเมื่อมันผ่านส่วนที่เหลือของวิธีการที่รอ
ในภายหลังเมื่อเสร็จสิ้นการรอคอยมันจะดำเนินการส่วนที่เหลือของวิธีการ async (ภายในบริบทที่จับ)
นี่คือสาเหตุที่ปัญหานี้เกิดขึ้นในโปรแกรมคอนโซลที่มีasync Main
:
จำไว้ว่าจากโพสต์บทนำของเราว่าวิธีการซิงค์จะกลับไปที่ผู้โทรก่อนที่จะเสร็จสมบูรณ์ สิ่งนี้ทำงานได้อย่างสมบูรณ์ในแอปพลิเคชั่น UI (วิธีนี้เพิ่งกลับไปที่ลูปเหตุการณ์ UI) และแอปพลิเคชัน ASP.NET (วิธีการส่งคืนเธรด แต่ยังคงคำขอไว้) มันไม่ได้ผลดีนักสำหรับโปรแกรม Console: หลักกลับไปที่ OS - ดังนั้นโปรแกรมของคุณจึงออก
ทางออกหนึ่งคือการให้บริบทของคุณเอง - "วนรอบหลัก" สำหรับโปรแกรมคอนโซลของคุณที่เข้ากันได้กับ async
ถ้าคุณมีเครื่องที่มี Async CTP คุณสามารถใช้GeneralThreadAffineContext
จากMy Documents \ Microsoft Visual Studio Async CTP \ Samples (C # Testing) หน่วยทดสอบ หรือคุณสามารถใช้AsyncContext
จากแพคเกจ Nito.AsyncEx NuGet ของฉัน
นี่คือตัวอย่างการใช้AsyncContext
; GeneralThreadAffineContext
มีการใช้งานเกือบเหมือนกัน:
using Nito.AsyncEx;
class Program
{
static void Main(string[] args)
{
AsyncContext.Run(() => MainAsync(args));
}
static async void MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
หรือคุณสามารถบล็อกเธรดคอนโซลหลักจนกว่างานอะซิงโครนัสของคุณจะเสร็จสมบูรณ์:
class Program
{
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
หมายเหตุการใช้GetAwaiter().GetResult()
; นี้หลีกเลี่ยงAggregateException
การตัดที่เกิดขึ้นถ้าคุณใช้หรือWait()
Result
ปรับปรุง 2017/11/30:ในฐานะของ Visual Studio 2017 ปรับปรุง 3 (15.3) ภาษาในขณะนี้สนับสนุนasync Main
- ตราบใดที่มันจะกลับหรือTask
Task<T>
ดังนั้นตอนนี้คุณสามารถทำสิ่งนี้:
class Program
{
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
ความหมายดูเหมือนจะเหมือนกับGetAwaiter().GetResult()
รูปแบบการบล็อกเธรดหลัก อย่างไรก็ตามยังไม่มีข้อมูลจำเพาะภาษาสำหรับ C # 7.1 ดังนั้นนี่เป็นเพียงข้อสมมติฐาน