Task.WhenAll
.NET Core 3.0'da çalışırken yöntemle ilgili meraklı bir gözlem yaptım . Basit bir Task.Delay
görevi tek bir argüman olarak Task.WhenAll
geç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.Delay
gö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 task
ve 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 await
tü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.WhenAny
yerine kaydırmak Task.WhenAll
.
Başka bir gözlem: Sargının bir içine sarılmasının Task.Run
sü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.Delay
gelen 100
için 1000
o zaman tamamlanmaz böylece await
ed.
await Task.WhenAll(new[] { task });
?