I am struggling with a timing issue I have in Docker
Here is my test code:
using System.Diagnostics;
DisplayStopWatchResolution();
var timer = new Stopwatch();
//begin the test
while (true)
{
timer.Restart();
timer.Start();
//Thread.Sleep(1);
await Task.Delay(1).ConfigureAwait(false);
timer.Stop();
Console.WriteLine($"Task time {timer.Elapsed.TotalMilliseconds}");
}
static void DisplayStopWatchResolution()
{
if (Stopwatch.IsHighResolution)
{
Console.WriteLine("Operations timed using the system's high-resolution performance counter.");
}
else
{
Console.WriteLine("Operations timed using the DateTime class.");
}
long frequency = Stopwatch.Frequency;
Console.WriteLine(" Timer frequency in ticks per second = {0}",
frequency);
long nanosecPerTick = (1000L * 1000L * 1000L) / frequency;
Console.WriteLine(" Timer is accurate within {0} nanoseconds",
nanosecPerTick);
}
What I want is for the system to wait around 1ms.
However I am getting these results:
-
Windows | Timer is accurate within 100 nanoseconds:
- await Task.Delay(1).ConfigureAwait(false); is roughly 1.942 ms (acceptable)
- Thread.Sleep(1) is again roughly 1.942ms (acceptable)
-
Linux (ubuntu on WSL using docker) | Timer is accurate within 1 nanoseconds:
- await Task.Delay(1).ConfigureAwait(false) is roughly 10 ms (my bad case)
- Thread.Sleep() is 1.0712ms (really good)
-
Linux (ubuntu running the exe):
- await Task.Delay(1).ConfigureAwait(false); is roughly 1.942 ms (acceptable)
- Thread.Sleep(1) is again roughly 1.942ms (acceptable)
I need to use docker and would prefer to use Task.Delay() as to not block the thread however with the performance being 10x what is should b, it’s not really an option.
My question is how to fix Task.Delay() under Docker linux to not be so slow.
Thank you
2
Answers
This is not the intended use case for
Task.Delay()
. There is no guarantee that the awaitable will return control to the task immediately once the delay has elapsed. That’s not how cooperative concurrency works (ie. asynchronous). It depends entirely on what other tasks are running and how frequently they cede control of the event loop.Task.Delay()
is for retying a bit of code, but backing off a bit so as not to overload the resource you are trying to use (like an HTTP server). It is not for fine-grained time synchronisation.If you want to give other tasks a chance to execute before continuing in a busy loop then use
await Task.Yield()
. This will allow other tasks to execute (if they exist and are ready to execute), otherwise control is returned to the task immediately.It is unclear why you want to wait for 1 ms. Without that information it is hard to suggest how to make system wait so short time.
As you have noted
Thread.Sleep
andTask.Delay
respond differently. As mentioned in Microsoft documentationThread.Sleep
suspends running thread for given time. That means that same thread is activated after wait time and it will not respond to any calls while suspended.Task.Delay
delays the task but you can call it while the delay is in effect. When delay finishes code continues running but probably in another thread because context is a task not a thread.The difference is that you can introduce cancellation token for
Task.Delay
. It is useful if wait time is long and you want to abort waiting like when waiting external device that doesn’t respond for a while.Is the question: How can I set up accurate timer?
I know Windows OS sets restrictions how accurate and fast a timer can be.
There are few options to choose from depending on your needs. But it seems like Windows OS typically caps to ~15 ms speed. HighPrecisionTimer tries to deal with that problem.
Here are few possible solutions depending on what kind of problem you are trying to solve.
I hope you’ll find answer from these information paths. But as I said earlier, it is unclear why do you want to have 1 ms delay.
Is it because external device, UI event, accuracy in some other logic or what. Why would also narrow down what libraries could be recommended to achieve that short delay.