ฉันจะรอให้void asyncวิธีการทำงานให้เสร็จได้อย่างไร
ตัวอย่างเช่นฉันมีฟังก์ชั่นด้านล่าง:
async void LoadBlahBlah()
{
await blah();
...
}
ตอนนี้ฉันต้องการให้แน่ใจว่าทุกอย่างถูกโหลดก่อนดำเนินการต่อที่อื่น
ฉันจะรอให้void asyncวิธีการทำงานให้เสร็จได้อย่างไร
ตัวอย่างเช่นฉันมีฟังก์ชั่นด้านล่าง:
async void LoadBlahBlah()
{
await blah();
...
}
ตอนนี้ฉันต้องการให้แน่ใจว่าทุกอย่างถูกโหลดก่อนดำเนินการต่อที่อื่น
คำตอบ:
วิธีที่ดีที่สุดคือการทำเครื่องหมายฟังก์ชั่นเฉพาะในกรณีที่มันเป็นไฟและลืมวิธีการถ้าคุณต้องการที่จะรอที่คุณควรจะทำเครื่องหมายว่าasync voidasync Task
ในกรณีที่คุณยังต้องการรออยู่ให้ปิดแผ่นให้เหมือนกัน await Task.Run(() => blah())
await Task.Run(() => An_async_void_method_I_can_not_modify_now())
await Task.Run(() => blah())กำลังทำให้เข้าใจผิด สิ่งนี้ไม่ได้รอฟังก์ชั่น async ให้เสร็จสมบูรณ์blahแต่จะรอการสร้าง (เล็กน้อย) ของงานและทำต่อไปทันทีก่อนที่จะblah()เสร็จสมบูรณ์
Thread.Sleepไม่ใช่ async คำถามนี้เกี่ยวกับการรอasync voidฟังก์ชั่นพูดasync void blah() { Task.Delay(10000); }
หากคุณสามารถเปลี่ยนลายเซ็นของฟังก์ชั่นของคุณasync Taskแล้วคุณสามารถใช้รหัสที่แสดงที่นี่
ทางออกที่ดีที่สุดคือการใช้ async Taskทางออกที่ดีที่สุดคือการใช้งานคุณควรหลีกเลี่ยงasync voidด้วยเหตุผลหลายประการซึ่งหนึ่งในนั้นคือการเรียงความ
หากไม่สามารถทำการคืนค่าได้Task(เช่นเป็นตัวจัดการเหตุการณ์) คุณสามารถใช้SemaphoreSlimเพื่อให้สัญญาณวิธีการได้เมื่อกำลังจะออก ลองทำสิ่งนี้ในfinallyบล็อก
ทำ AutoResetEvent ให้เรียกใช้ฟังก์ชั่นจากนั้นรอ AutoResetEvent แล้วตั้งค่าภายใน async เป็นโมฆะเมื่อคุณทราบว่าเสร็จสิ้น
นอกจากนี้คุณยังสามารถรองานที่ส่งคืนจากโมฆะ async ของคุณ
คุณไม่จำเป็นต้องทำอะไรด้วยตนเองawaitคำหลักหยุดการทำงานของฟังก์ชันชั่วคราวจนกว่าจะblah()ส่งคืน
private async void SomeFunction()
{
var x = await LoadBlahBlah(); <- Function is not paused
//rest of the code get's executed even if LoadBlahBlah() is still executing
}
private async Task<T> LoadBlahBlah()
{
await DoStuff(); <- function is paused
await DoMoreStuff();
}
Tเป็นชนิดของการblah()ส่งคืนวัตถุ
คุณไม่สามารถawaitใช้voidงานฟังก์ชันLoadBlahBlah()ได้void
LoadBlahBlah()จนจบไม่ใช่blah()
ฉันรู้ว่านี่เป็นคำถามเก่า แต่ยังคงเป็นปัญหาที่ฉันยังคงเดินต่อไปและยังไม่มีวิธีแก้ปัญหาที่ชัดเจนในการทำอย่างถูกต้องเมื่อใช้ async / รอในวิธีการเซ็นชื่อเป็นโมฆะ async
อย่างไรก็ตามฉันสังเกตเห็นว่า. Wait () ทำงานอย่างถูกต้องภายในวิธี void
และเนื่องจาก async เป็นโมฆะและโมฆะมีลายเซ็นเดียวกันคุณอาจต้องทำดังต่อไปนี้
void LoadBlahBlah()
{
blah().Wait(); //this blocks
}
async / await ที่สับสนพอไม่ได้บล็อคในโค้ดถัดไป
async void LoadBlahBlah()
{
await blah(); //this does not block
}
เมื่อคุณถอดรหัสโค้ดของฉันฉันเดาว่า async void จะสร้างงานภายใน (เช่นเดียวกับ async Task) แต่เนื่องจากลายเซ็นไม่รองรับการส่งคืนงานภายในนั้น
ซึ่งหมายความว่าวิธีการโมฆะ async ภายในจะยังสามารถ "รอ" วิธีการซิงค์ภายใน แต่ภายนอกไม่สามารถรู้ได้เมื่องานภายในเสร็จสมบูรณ์
ดังนั้นข้อสรุปของฉันคือโมฆะ async ทำงานได้ตามที่ตั้งใจและถ้าคุณต้องการข้อเสนอแนะจากงานภายในแล้วคุณต้องใช้ลายเซ็นงาน async แทน
หวังว่าการเที่ยวของฉันจะสมเหตุสมผลกับทุกคนที่กำลังมองหาคำตอบด้วย
แก้ไข: ฉันสร้างโค้ดตัวอย่างและถอดรหัสเพื่อดูว่าเกิดอะไรขึ้นจริง
static async void Test()
{
await Task.Delay(5000);
}
static async Task TestAsync()
{
await Task.Delay(5000);
}
เปลี่ยนเป็น (แก้ไข: ฉันรู้ว่ารหัสร่างกายไม่ได้อยู่ที่นี่ แต่ใน statemachines แต่ statemachines เหมือนกันโดยทั่วไปดังนั้นฉันจึงไม่ต้องกังวลเพิ่ม)
private static void Test()
{
<Test>d__1 stateMachine = new <Test>d__1();
stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
}
private static Task TestAsync()
{
<TestAsync>d__2 stateMachine = new <TestAsync>d__2();
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
ทั้ง AsyncVoidMethodBuilder หรือ AsyncTaskMethodBuilder จะมีรหัสใด ๆ ในวิธีการเริ่มต้นที่จะบอกใบ้ให้พวกเขาบล็อกและจะทำงานแบบอะซิงโครนัสเสมอหลังจากที่เริ่มต้นแล้ว
ความหมายหากไม่มีภารกิจที่ส่งคืนจะไม่มีวิธีตรวจสอบว่ามันสมบูรณ์หรือไม่
อย่างที่คาดไว้มันจะเริ่มงานที่กำลังทำงาน async เท่านั้นและจากนั้นจะดำเนินการต่อในรหัส และ async Task อันดับแรกมันจะเริ่ม Task จากนั้นก็คืนค่ามัน
ดังนั้นฉันเดาว่าคำตอบของฉันจะไม่ใช้ async เป็นโมฆะถ้าคุณจำเป็นต้องรู้เมื่องานเสร็จนั่นคือสิ่งที่ async Task ใช้