WaitAll ve WhenAll


Yanıtlar:


504

Task.WaitAll her şey tamamlanana kadar mevcut iş parçacığını engeller.

Task.WhenAllher şey tamamlanana kadar bekleme eylemini temsil eden bir görev döndürür .

Bu, zaman uyumsuz bir yöntemden şunları kullanabileceğiniz anlamına gelir:

await Task.WhenAll(tasks);

... yani her şey tamamlandığında yönteminiz devam edecek, ancak o zamana kadar takılmak için bir ileti dizisi bağlamayacaksınız.


2
Çok okuduktan sonra, async'in
Vince Panuccio

7
@Vince: Bence "iş parçacığı ile ilgisi yok" abartılı olduğunu ve zaman uyumsuz işlemlerin iş parçacıkları ile nasıl etkileşim kurduğunu anlamak önemlidir.
Jon Skeet

6
@KevinBui: Hayır, engellememeli - geri dönen görevi bekleyecekWhenAll , ancak iş parçacığını engellemekle aynı şey değil.
Jon Skeet

1
@JonSkeet Belki de bu ikisi arasındaki kesin ayrım benim için çok incedir. Beni (ve muhtemelen geri kalanımızı) farkı netleştirecek bazı referanslara yönlendirebilir misiniz?
CatShoes

125
@CatShoes: Pek değil - zaten elimden geldiğince açıkladım. Bence bir benzetme verebilirim - bir paket servisi sipariş etmek ve daha sonra gelmesini bekleyen kapının yanında durmak, bir paket servisi sipariş etmek, başka şeyler yapmak ve sonra kurye geldiğinde kapıyı açmak arasındaki fark gibi ...
Jon Skeet

51

JonSkeet'in cevabı, farkı tipik olarak mükemmel bir şekilde açıklarken, başka bir fark daha vardır: istisna yönetimi .

Task.WaitAllBir atar AggregateExceptiongörevlerden herhangi birini atar ve tüm atılan istisnalar inceleyebilir zaman. awaitİçinde await Task.WhenAllunwraps AggregateExceptionve 'döner' sadece ilk istisna.

Aşağıdaki program await Task.WhenAll(taskArray)çıktı ile yürütüldüğünde aşağıdaki gibidir.

19/11/2016 12:18:37 AM: Task 1 started
19/11/2016 12:18:37 AM: Task 3 started
19/11/2016 12:18:37 AM: Task 2 started
Caught Exception in Main at 19/11/2016 12:18:40 AM: Task 1 throwing at 19/11/2016 12:18:38 AM
Done.

Aşağıdaki program çıktıyla yürütüldüğünde Task.WaitAll(taskArray)çıktı aşağıdaki gibidir.

19/11/2016 12:19:29 AM: Task 1 started
19/11/2016 12:19:29 AM: Task 2 started
19/11/2016 12:19:29 AM: Task 3 started
Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 1 throwing at 19/11/2016 12:19:30 AM
Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 2 throwing at 19/11/2016 12:19:31 AM
Caught AggregateException in Main at 19/11/2016 12:19:32 AM: Task 3 throwing at 19/11/2016 12:19:32 AM
Done.

Program:

class MyAmazingProgram
{
    public class CustomException : Exception
    {
        public CustomException(String message) : base(message)
        { }
    }

    static void WaitAndThrow(int id, int waitInMs)
    {
        Console.WriteLine($"{DateTime.UtcNow}: Task {id} started");

        Thread.Sleep(waitInMs);
        throw new CustomException($"Task {id} throwing at {DateTime.UtcNow}");
    }

    static void Main(string[] args)
    {
        Task.Run(async () =>
        {
            await MyAmazingMethodAsync();
        }).Wait();

    }

    static async Task MyAmazingMethodAsync()
    {
        try
        {
            Task[] taskArray = { Task.Factory.StartNew(() => WaitAndThrow(1, 1000)),
                                 Task.Factory.StartNew(() => WaitAndThrow(2, 2000)),
                                 Task.Factory.StartNew(() => WaitAndThrow(3, 3000)) };

            Task.WaitAll(taskArray);
            //await Task.WhenAll(taskArray);
            Console.WriteLine("This isn't going to happen");
        }
        catch (AggregateException ex)
        {
            foreach (var inner in ex.InnerExceptions)
            {
                Console.WriteLine($"Caught AggregateException in Main at {DateTime.UtcNow}: " + inner.Message);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Caught Exception in Main at {DateTime.UtcNow}: " + ex.Message);
        }
        Console.WriteLine("Done.");
        Console.ReadLine();
    }
}

13
en büyük pratik fark istisna yönetimidir. Gerçekten mi? Çünkü bu gerçekten en büyük pratik fark değil. En büyük pratik fark, async ve bloke olmayan, diğerinin bloke olduğu yerdir. Bu, istisnaları nasıl ele aldığından çok daha önemlidir.
Liam

5
Bunu işaret ettiğiniz için teşekkürler. Bu açıklama şu anda çalıştığım senaryoda faydalı oldu. Belki de "en büyük pratik fark" değil, kesinlikle iyi bir çağrı.
Urk

En büyük pratik fark olan istisna işleme, await t1; await t2; await t3;vsawait Task.WhenAll(t1,t2,t3);
frostshoxx

1
Bu kural dışı durum davranışı burada dokümanlarla çelişmiyor mu ( docs.microsoft.com/en-us/dotnet/api/… ) "Sağlanan görevlerden herhangi biri hatalı bir durumda tamamlanırsa, döndürülen görev de Hatalı bir durumda tamamlanır , bunun istisnaları, verilen görevlerin her birinden kaydırılmamış istisnalar kümesinin toplanmasını içerecektir. "
Dasith Wijes

1
Bunun awaitiki yöntem arasındaki fark değil, bir eser olduğunu düşünüyorum . Her ikisi de AggregateExceptiondoğrudan ya da bir mülk ( Task.Exceptionmülk) aracılığıyla bir a yayar .
Theodor Zoulias

20

Farkın bir örneği olarak - bir göreve sahipseniz Task.WaitAll(), kullanıcı arayüzü iş parçacığı engellenir ve kullanıcı arayüzü hiçbir zaman güncellenmezse , UI iş parçacığıyla bir şey yapar (örneğin, bir Öykü Tahtasında bir animasyonu temsil eden bir görev) . kullanırsanız await Task.WhenAll(), UI iş parçacığı engellenmez ve UI güncellenir.


7

Onlar ne yapar:

  • Dahili olarak her ikisi de aynı şeyi yapar.

Fark ne:

  • WaitAll bir engelleme çağrısıdır
  • WhenAll - not - kodu yürütülmeye devam edecek

Aşağıdakileri kullanın:

  • Sonuç beklemeden devam edemediğinde
  • Ne zaman bildirilecek, engellenmeyen

1
@MartinRhodes Ama hemen bekliyor, ancak bazı diğer çalışmaları ile devam eder ve ne yapsanız o zaman bunu bekliyor? WaitAllAnladığım kadarıyla bu olasılığınız yok.
Jeppe

@Jeppe Başka bir iş Task.WaitAll yaptıktan sonra sadece aramayı değiştirmez miydin? Yani, görevlerine başladıktan hemen sonra aramak yerine.
PL
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.