Task.WhenAll.NET Core 3.0'da çalışırken yöntemle ilgili meraklı bir gözlem yaptım . Basit bir Task.Delaygörevi tek bir argüman olarak Task.WhenAllgeçtim ve sarılmış görevin orijinal göreve aynı şekilde davranmasını bekledim. Ancak durum böyle değil. Orijinal görevin devamları eşzamansız olarak (istenir) Task.WhenAll(task)yürütülür ve çoklu sarmalayıcıların süreleri birbiri ardına eşzamanlı olarak yürütülür (bu istenmeyen bir durumdur).
İşte bu davranışın bir demosu . Dört işçi görevi aynı Task.Delaygörevi tamamlamak için bekliyor ve sonra ağır bir hesaplama ile devam ediyor (a ile simüle edilmiş Thread.Sleep).
var task = Task.Delay(500);
var workers = Enumerable.Range(1, 4).Select(async x =>
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} before await");
await task;
//await Task.WhenAll(task);
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}" +
$" [{Thread.CurrentThread.ManagedThreadId}] Worker{x} after await");
Thread.Sleep(1000); // Simulate some heavy CPU-bound computation
}).ToArray();
Task.WaitAll(workers);
İşte çıktı. Dört devam, farklı iş parçacıklarında (paralel olarak) beklendiği gibi çalışıyor.
05:23:25.511 [1] Worker1 before await
05:23:25.542 [1] Worker2 before await
05:23:25.543 [1] Worker3 before await
05:23:25.543 [1] Worker4 before await
05:23:25.610 [4] Worker1 after await
05:23:25.610 [7] Worker2 after await
05:23:25.610 [6] Worker3 after await
05:23:25.610 [5] Worker4 after await
Şimdi çizgiye yorum yapar await taskve aşağıdaki satırı kaldırırsam await Task.WhenAll(task), çıktı oldukça farklıdır. Tüm devamlar aynı iş parçacığında çalışıyor, bu nedenle hesaplamalar paralel değil. Her hesaplama bir öncekinin tamamlanmasından sonra başlar:
05:23:46.550 [1] Worker1 before await
05:23:46.575 [1] Worker2 before await
05:23:46.576 [1] Worker3 before await
05:23:46.576 [1] Worker4 before await
05:23:46.645 [4] Worker1 after await
05:23:47.648 [4] Worker2 after await
05:23:48.650 [4] Worker3 after await
05:23:49.651 [4] Worker4 after await
Şaşırtıcı bir şekilde, bu sadece her işçi farklı bir ambalaj beklediğinde olur. Sarıcıyı önceden tanımlarsam:
var task = Task.WhenAll(Task.Delay(500));
... ve sonra awaittüm işçilerin içindeki aynı görev, davranış ilk durumla aynıdır (eşzamansız devamlar).
Sorum şu: bu neden oluyor? Aynı görevin farklı sarmalayıcılarının devamlarının aynı iş parçacığında, eşzamanlı olarak yürütülmesine ne sebep olur?
Not: bir görevi aynı garip davranışla sonuçlamak Task.WhenAnyyerine kaydırmak Task.WhenAll.
Başka bir gözlem: Sargının bir içine sarılmasının Task.Runsüreksizliği asenkronize etmesini bekledim . Ama olmuyor. Aşağıdaki satırın devamları hala aynı iş parçacığında (eşzamanlı olarak) yürütülür.
await Task.Run(async () => await Task.WhenAll(task));
Açıklama: Yukarıdaki farklılıklar, .NET Core 3.0 platformunda çalışan bir Konsol uygulamasında gözlemlenmiştir. .NET Framework 4.8'de, orijinal görevi veya görev sarmalayıcıyı beklemek arasında bir fark yoktur. Her iki durumda da, devamlar aynı iş parçacığında senkronize olarak yürütülür.
Task.WhenAll
Task.Delaygelen 100için 1000o zaman tamamlanmaz böylece awaited.
await Task.WhenAll(new[] { task });?