What is causing these discrete spikes in execution time when waiting for Tasks to complete? And why is using WhenAll slower than just looping really quickly and checking if all the tasks are complete? This is a simplified example, but was created because we saw seemingly unnecessary delay when calling WhenAll. NativeAOT doesn't seem to be as effected, so maybe some unnecessary JITing?
using System.Diagnostics;
namespace ConsoleApp1
{
internal class Program
{
static async Task Main()
{
for (int i = 1; i <= 100; i+=1)
{
await RunTest(i);
}
}
public static async Task RunTest(int count)
{
var sw = Stopwatch.StartNew();
var tasks = new List<Task>();
// Construct started tasks
for (int i = 0; i < count; i++)
{
tasks.Add(Task.Run(() => Thread.Sleep(250)));
}
// Test 1, WhenAll
//await Task.WhenAll(tasks);
// Test 2, 10ms loop
bool completed = false;
while (!completed)
{
await Task.Delay(10);
completed = tasks.All(t => t.IsCompleted);
}
Console.WriteLine($"{count},{sw.Elapsed.TotalSeconds}");
}
}
}
The data above was all collected from running a self-contained exe from command line. But when run in VS it doesn't seem to be a garbage collection issue, which I suspected, since the VS diagnostics don't show any garbage collection marks.
EDIT: Once putting real load on the CPU and not sleeping, the differences and discrete bumps disappeared.