How to enter an exact small delay in a task without CPU overload?

I implement a communication algorithm to send information periodically and very quickly, i.e. 1 ms between packets. I have a functional version that uses Tasks to send packages. Here is an example of my code:

private void Work() { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); while (!cancellationTokenSource.Token.IsCancellationRequested) { if (!Pack.PeriodicOn) cancellationTokenSource.Cancel(); // Time used to send the packs before the interval time double tolerance = Pack.Interval * 0.2F; // In case of interval bigger than 25ms send pasks only 5ms before if (tolerance > 5) tolerance = 5; TimeSpan timeSpan = stopwatch.Elapsed; // The waiting time is controlled by the condition below, if the condition is false, the while loop continues execution // Send the information a little bit before to interval time to deal with the transmision delay if (Pack.LastSent.TotalMilliseconds == 0 || timeSpan.TotalMilliseconds - Pack.LastSent.TotalMilliseconds >= (Pack.Interval - tolerance)) { SendData(Pack); Pack.LastSent = timeSpan; } } Pack.LastSent = new TimeSpan(0); } 

My problem is that CPU usage is increasing to undesirable levels. I know that I can avoid this by introducing some delay, but Thread.Sleep (1) is very inaccurate and the real transmission interval between packets increases if I use Task.Delay (1) wait, it seems to have the same effect.

Does anyone have an alternative way of introducing, precisely, delays in tasks?

Thanks in advance!

+6
source share
3 answers

Windows is not an operating system, so timers are not guaranteed to work for sure. Typical system clocks have an accuracy of about 15 ms. However, you can get more accurate events than the standard System.Threading.Timer . The Windows API has timers designed for multimedia scripts that can fire at more precise intervals. I am updating the code in the GitHub repository that I support, HighPrecisionTimer , which uses this API to enable the MultimediaTimer.Delay method based on the task:

 private static async Task RunEveryMillisecond(CancellationToken token) { Stopwatch s = Stopwatch.StartNew(); TimeSpan prevValue = TimeSpan.Zero; int i = 0; while (true) { Console.WriteLine(s.ElapsedMilliseconds); await MultimediaTimer.Delay(1, token); if (Console.KeyAvailable) { return; } i++; } } 

Please note that this works approximately every 1.5 ms on my system, and it can still hit the processor for about 10% at startup, so that it does not neglect to hit system resources. The standard timer method included in the project is a bit more accurate and efficient (less processor costs, ~ 1%) to run methods at the 1 ms level. I assume that the task-based delay method has more distribution and garbage collection costs.

Please note that using this API can have side effects, such as shortening battery life. However, this is useful for test-type scenarios where shorter timings are required.

0
source

How to enter exact small delay [1 ms] without CPU overload [on Windows]?

You can't, sorry. The windows system scheduler is only slightly configurable (by selecting Adjust for best performance of Applications in the advanced system properties dialog box for Windows Server or setting the registry value ), but it will not go into the sub-millisecond territory. If this happened, the performance of the entire system would suffer unacceptably.

Depending on your hardware, I think it’s possible to reduce the system clock resolution to 0.5 ms; however, the minimum thread quantum you can set is 6, which will require two clock cycles to reduce to 0. Thus, you will still get a 1 ms quantum, which is at least twice as slow as you need . And, of course, you will reduce battery life by ~ 15% (from what I read).

For more information, read Windows Internal Documents .

+1
source

you can start many consecutive threads, say n (n = 10 or 20, etc.) (n is the number of threads) after 1 ms of delay, and in each task you can wait n milliseconds.

0
source

Source: https://habr.com/ru/post/1013403/


All Articles