3 ms·
I appreciate the long reply (no sarcasm) and the compliment regarding the salary haha (it makes for a nice aspirational goal, to have good total comp). I probab
by neonsunset 3y ago
I appreciate the long reply (no sarcasm) and the compliment regarding the salary haha (it makes for a nice aspirational goal, to have good total comp). I probably can't respond to the whole post but feel like we can come to an understanding.
You mentioned 10_000 perceptibly parallel tasks so I threw together a small example - what if we had 10_000_000 concurrently executed tasks instead? This takes 1.2-1.5GB of RAM to run but it can give you a good showcase that .NET ThreadPool can take a lot of punishment and this is far from the worst you could see in one enterprise codebase or another:
var tenMillionTasks = Enumerable
.Range(0, 10_000_000)
.Select(async i =>
{
// Force the yield - this way the methods will continue the execution
// in the form of scheduled continuations (work items), so that we pay
// for context switching too, similar to a more realistic scenario.
await Task.Yield();
for (var j = 10_000; j >= 0; j--)
{
// This is an okay proxy for doing some work since the
// JIT is fairly conservative and won't auto-vectorize this
// because its computation budget is prioritized on more impactful
// optimizations like inlining, CSE, devirtualization, etc.
// (this is completrly compensated by portable SIMD API)
i++;
}
return i;
});
// Scales linearly with the number of CPU cores
var results = await Task.WhenAll(tenMillionTasks);
var average = results.Average();
Console.WriteLine($"Done! The avg is {average}");
You can try it yourself if you're interested. To do so you can get an SDK from https://dot.net/download https://dot.net/download, execute 'dotnet new console', paste the code to Program.cs and then execute 'dotnet run -c Release'. This is more stressing to the runtime and is likely more fair than another comparison posts a year ago or so here on HN where that evaluated various runtimes by having the task simply wait for a period of time. Nonetheless, you can replicate that too by adding 'var delay = Task.Delay(TimeSpan.FromSeconds(5))' before tasks variable and replacing the lambda passed to .Select with 'async _ => await delay' to see how small the task overhead is.
- pdimitar 3y agoI appreciate you putting this together. :) If I am wrong, I'd be happy. It would be about time the big software stacks took proper parallelism to heart.