Geçersiz bir zaman uyumsuzluk yöntemi bekleyin


155

Bir void asyncyöntemin işini bitirmesini nasıl bekleyebilirim ?

Örneğin, aşağıdaki gibi bir işlevi var:

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

şimdi başka bir yere devam etmeden önce her şeyin yüklendiğinden emin olmak istiyorum.

Yanıtlar:


234

En iyi uygulama, işlevi async voidyalnızca yangın ve unut yöntemiyse işaretlemektir, beklemek istiyorsanız, olarak işaretlemelisiniz async Task.

Hala beklemek istiyorsan, o zaman böyle sar await Task.Run(() => blah())


Blah açık bir şekilde görevine geri dönüyor ve neden async imzasını beklemeden çağırıyorsunuz? VS bile size bu konuda uyarı verecektir.
batmaci

8
await Task.Run(() => An_async_void_method_I_can_not_modify_now())
themefield

1
await Task.Run(() => blah())yanıltıcıdır. Bu, zaman uyumsuzluk işlevinin tamamlanmasını beklemez blah, sadece görevin (önemsiz) oluşturulmasını bekler ve blah()tamamlanmadan hemen önce devam eder .
Jonathan Lidbeck

@JonathanLidbeck "falan yanlış olmadan hemen önce devam ediyor." Task.Run (() => Thread.Sleep (10_000)) "u deneyin, görev herhangi bir sonraki satırı çalıştırmadan önce 10 saniye + beklenir
Rohit Sharma

@RohitSharma, bu örnek için doğrudur, ancak Thread.Sleepeşzamansız değildir. Bu soru bir async voidişlevi beklemekle ilgili , diyelimasync void blah() { Task.Delay(10000); }
Jonathan Lidbeck

59

İşlevinizin imzasını şu şekilde değiştirebilirsiniz: buradaasync Task sunulan kodu kullanabilirsiniz


27

En iyi çözüm kullanmaktır async Task. Bir kaçınılmazlığı async voidolan çeşitli nedenlerden kaçınmalısınız .

Yöntem ise olamaz dönmek için yapılacak Task(örneğin, bir olay işleyicisi var), o zaman kullanabilirsiniz SemaphoreSlimo çıkmak üzereyken yöntem sinyali olması. Bunu bir finallyblokta yapmayı düşünün .


1

bir AutoResetEvent yapın, işlevi çağırın, sonra AutoResetEvent'i bekleyin ve bittiğini bildiğinizde async void içinde ayarlayın.

Ayrıca, boş zaman uyumsuzluğunuzdan dönen bir Görevi de bekleyebilirsiniz


1

Manuel olarak herhangi bir şey yapmanıza gerek yoktur, awaitanahtar kelime blah()geri dönene kadar işlev yürütmeyi duraklatır .

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();
}

Tnesne blah()döndürme türüdür

Gerçekten awaitbir voidişlev LoadBlahBlah()yapamazsın, bu yüzden olamazvoid


LoadBlahBlah()Bitirmek için beklemek istiyorum , değilblah()
MBZ

10
Maalesef zaman uyumsuz geçersiz yöntemler yürütmeyi duraklatmaz (zaman uyumsuz Görev yöntemlerinin aksine)
ghord

-1

Bunun eski bir soru olduğunu biliyorum, ama bu hala yürümeye devam ettiğim bir sorun ve yine de async / await'i bir async geçersiz imza yönteminde kullanırken bunu doğru bir şekilde yapmak için hala net bir çözüm yok.

Ancak, .Wait () void yöntemi içinde düzgün çalıştığını fark ettim.

ve eşzamansız boşluk ve boşluk aynı imzayı taşıdığından, aşağıdakileri yapmanız gerekebilir.

void LoadBlahBlah()
{
    blah().Wait(); //this blocks
}

Kafa karıştırıcı bir şekilde yeterli zaman uyumsuzluğu / beklemesi bir sonraki kodu engellemez.

async void LoadBlahBlah()
{
    await blah(); //this does not block
}

Kodunuzu koda dönüştürdüğünüzde, tahminim asenkron boşluğun dahili bir Görev (tıpkı zaman uyumsuz Görev gibi) oluşturmasıdır, ancak imza bu dahili Görevleri döndürmeyi desteklemediğinden

bu, dahili olarak asenkron boşluk yönteminin dahili olarak asenkron yöntemleri hala "bekleyebileceği" anlamına gelir. ancak harici olarak dahili görevin ne zaman tamamlandığını bilemez.

Sonuç olarak, asenkron boşluğun amaçlandığı gibi çalıştığı ve dahili Görev'den geri bildirime ihtiyacınız varsa, bunun yerine asenkron Görev imzasını kullanmanız gerekir.

Umarım başıboşum da cevap arayan herkese mantıklı geliyor.

Düzenleme: Bazı örnek kodlar yaptım ve aslında neler olduğunu görmek için koda.

static async void Test()
{
    await Task.Delay(5000);
}

static async Task TestAsync()
{
    await Task.Delay(5000);
}

Dönüşür (değiştir: Vücut kodunun burada değil, statemachines'de olduğunu biliyorum, ancak statemachines temelde aynıydı, bu yüzden onları eklemeye zahmet etmedim)

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 veya AsyncTaskMethodBuilder aslında Start yönteminde engellenecekleri ima edecek ve başlatıldıktan sonra her zaman eşzamansız olarak çalışacak herhangi bir koda sahip değildir.

yani geri dönen Görev olmadan, tamamlanıp tamamlanmadığını kontrol etmenin bir yolu olmazdı.

beklendiği gibi, yalnızca zaman uyumsuz çalışan Görev'i başlatır ve sonra kodda devam eder. ve zaman uyumsuz Görev, önce Görev'i başlatır ve sonra geri döndürür.

bu yüzden cevabım hiçbir zaman async void'i kullanmak değildir, görevin ne zaman yapıldığını bilmeniz gerekiyorsa, async Task'ın amacı budur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.