รอวิธีการ void async


155

ฉันจะรอให้void asyncวิธีการทำงานให้เสร็จได้อย่างไร

ตัวอย่างเช่นฉันมีฟังก์ชั่นด้านล่าง:

async void LoadBlahBlah()
{
    await blah();
    ...
}

ตอนนี้ฉันต้องการให้แน่ใจว่าทุกอย่างถูกโหลดก่อนดำเนินการต่อที่อื่น

คำตอบ:


234

วิธีที่ดีที่สุดคือการทำเครื่องหมายฟังก์ชั่นเฉพาะในกรณีที่มันเป็นไฟและลืมวิธีการถ้าคุณต้องการที่จะรอที่คุณควรจะทำเครื่องหมายว่าasync voidasync Task

ในกรณีที่คุณยังต้องการรออยู่ให้ปิดแผ่นให้เหมือนกัน await Task.Run(() => blah())


เห็นได้ชัดว่า blah กลับมาทำงานและมีลายเซ็นของ async ทำไมคุณต้องโทรหาโดยไม่รอ แม้ VS จะเตือนคุณเกี่ยวกับเรื่องนี้
batmaci

8
await Task.Run(() => An_async_void_method_I_can_not_modify_now())
คะแนน

1
await Task.Run(() => blah())กำลังทำให้เข้าใจผิด สิ่งนี้ไม่ได้รอฟังก์ชั่น async ให้เสร็จสมบูรณ์blahแต่จะรอการสร้าง (เล็กน้อย) ของงานและทำต่อไปทันทีก่อนที่จะblah()เสร็จสมบูรณ์
Jonathan Lidbeck

@JonathanLidbeck คำสั่ง "ดำเนินการต่อทันทีก่อน blah ผิดลอง" รอ Task.Run (() => Thread.Sleep (10_000)) "งานจะถูกรอ 10 วินาที + ก่อนดำเนินการบรรทัดถัดไป
Rohit Sharma

@RohitSharma ที่ถูกต้องสำหรับตัวอย่างของคุณ แต่Thread.Sleepไม่ใช่ async คำถามนี้เกี่ยวกับการรอasync voidฟังก์ชั่นพูดasync void blah() { Task.Delay(10000); }
Jonathan Lidbeck


27

ทางออกที่ดีที่สุดคือการใช้ async Taskทางออกที่ดีที่สุดคือการใช้งานคุณควรหลีกเลี่ยงasync voidด้วยเหตุผลหลายประการซึ่งหนึ่งในนั้นคือการเรียงความ

หากไม่สามารถทำการคืนค่าได้Task(เช่นเป็นตัวจัดการเหตุการณ์) คุณสามารถใช้SemaphoreSlimเพื่อให้สัญญาณวิธีการได้เมื่อกำลังจะออก ลองทำสิ่งนี้ในfinallyบล็อก


1

ทำ AutoResetEvent ให้เรียกใช้ฟังก์ชั่นจากนั้นรอ AutoResetEvent แล้วตั้งค่าภายใน async เป็นโมฆะเมื่อคุณทราบว่าเสร็จสิ้น

นอกจากนี้คุณยังสามารถรองานที่ส่งคืนจากโมฆะ async ของคุณ


1

คุณไม่จำเป็นต้องทำอะไรด้วยตนเอง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()
MBZ

10
แต่น่าเสียดายที่ async วิธีการเป็นโมฆะไม่หยุดการดำเนินการ (ไม่เหมือน async วิธี Task)
ghord

-1

ฉันรู้ว่านี่เป็นคำถามเก่า แต่ยังคงเป็นปัญหาที่ฉันยังคงเดินต่อไปและยังไม่มีวิธีแก้ปัญหาที่ชัดเจนในการทำอย่างถูกต้องเมื่อใช้ 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 ใช้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.