My end goal is to schedule many similar tasks to run repeatedly with a consistent period, and have them spread across their period to avoid CPU demand spikes.
For the first step, I've tried finding the right way to schedule tasks to run an exact duration later. None of my attempts at this step have worked.
public static void Main(string[] args)
{
Console.WriteLine("Entry");
const int n = 1000;
int[] times = new int[n];
Task[] tasks = new Task[n];
DateTime wctStart = DateTime.Now;
for (int i = 0; i < n; i++)
{
int ibv = i;
DateTime now = DateTime.Now;
// For n = 1,000 we expect s >= 1,000,000; wct >= 1,000
// n=1,000 -> s=30k-80k; wct=200
//tasks[i] = Task.Delay(1000)
// .ContinueWith(_ =>
// {
// times[ibv] = (DateTime.Now - now).Milliseconds;
// });
// n=1,000 -> s=190k-300k; wct=200-400
// This also takes 50 seconds and eats 2-3MB mem
//tasks[i] = Task.Run(delegate
//{
// Thread.Sleep(1000);
// times[ibv] = (DateTime.Now - now).Milliseconds;
//});
// n=1,000 -> s=30k-400k; wct=300-500
//tasks[i] = Task.Run(async () =>
//{
// await Task.Delay(1000);
// times[ibv] = (DateTime.Now - now).Milliseconds;
//});
}
foreach (Task task in tasks)
{
task.Wait();
}
int s = 0;
foreach (int v in times)
{
s += v;
}
int wct = (DateTime.Now - wctStart).Milliseconds;
Console.WriteLine($"s={s:N0}, wct={wct:N0}");
Console.ReadKey();
}
To run this code, uncomment one of the three options first.
I'm scheduling 1,000 tasks to run 1,000 milliseconds later. Each one gets an index and stores how many milliseconds after creation it ran. The values I'd expect, and what would indicate a correct solution, are uniform measurements of 1,000ms or perhaps a few ms more, and therefore a value of s
being not less than 1,000,000 but perhaps up to several thousand more, and a wct
wall clock time of at least 1,000, or greater by a similar proportion.
What I observe instead is that all three of these approaches give widely variable values of s
in different ranges all much less than 1,000,000, and narrowly variable values of wct
all much less than 1,000.
Why do these approaches apparently not work and how can they be fixed?