What is the most accurate Thread sleep method: Monitor.Wait vs System.Timer vs DispatchTimer vs Threading.Timer

Which .NET object (or method) is most accurate when starting a thread every XXX milliseconds? What are the tradeoffs?

For instance:

        int maxDurationMs = 1000;
        while (true)
        {
            DateTime dt = DateTime.UtcNow;
            DoQuickStuff()
            TimeSpan duration1 =  DateTime.UtcNow - dt;
            int sleepTime = maxDurationMs - duration1.Milliseconds;
            if (sleepTime > 0)
                System.Threading.Thread.Sleep(sleepTime);
        }

or

       // CPU Intensive, but fairly accurate
       int maxDurationMs = 1000;
        while (true)
        {
            DateTime dt = DateTime.UtcNow;
            DoQuickStuff()
            while (true)
            {
                if (dt.AddMilliseconds(maxDurationMs) >= DateTime.UtcNow)
                    break;
            }
        }

Alternative methods of doing the same thing, but with varying degrees of accuracy and trade-offs (CPU, etc.)

+3
source share
5 answers

, " " , , Windows..NET BCL , P/Invoke.

Stopwatch Thread.Sleep . , , , Thread.Sleep. , - , .

, , ThreadPriority.Highest . , .

+4

DateTime: 16 . (. )

, while System.Diagnostics.Stopwatch .

, , : , ( 30 , ). OpenTK GameWindow, RaiseUpdateFrame.

+4

Windows Timers, , , , , - RTOS .

:

API- ... , Windows , . Windows , , Windows . WM_TIMER , WM_PAINT, .

+2

Monitor.Wait, Thread , "", . +/- 1 . .

, , .NET. Windows. , ( ) .

+2

System.Timers.Timer 120 MS .

I can use the following method to get a timer with an accuracy of 1 ms with an interval of 1 minute. Shorter intervals may not achieve the same accuracy (plus DoWork () overheads play a role in this efficiency)

 public class SystemTimerTest
   {

    readonly System.Timers.Timer timerRecalcStatistics;
    readonly System.Diagnostics.Stopwatch stopwatchForRecalcStatistics = new System.Diagnostics.Stopwatch();


    public SystemTimerTest(TimeSpan range, DataOverwriteAction action)
    {
        int recalculateStatisticsEveryXMillseconds = 1000;

        timerRecalcStatistics = new System.Timers.Timer(recalculateStatisticsEveryXMillseconds);
        timerRecalcStatistics.AutoReset = true;
        timerRecalcStatistics.Elapsed += new System.Timers.ElapsedEventHandler(TimerRecalcStatisticsElapsed);
        timerRecalcStatistics.Interval = recalculateStatisticsEveryXMillseconds;
        timerRecalcStatistics.Enabled = true;


        this.maxRange = range;
        this.hashRunningTotalDB = new HashRunningTotalDB(action);
        this.hashesByDate = new HashesByDate(action);
        this.dataOverwriteAction = action;
    }


    private void TimerRecalcStatisticsElapsed(object source, System.Timers.ElapsedEventArgs e)
    {
        stopwatchForRecalcStatistics.Start();
        Console.WriteLine("The TimerRecalcStatisticsElapsed event was raised at {0}", e.SignalTime.ToString("o"));

         // DO WORK HERE


        stopwatchForRecalcStatistics.Stop();
        double timeBuffer  = GetInterval(IntervalTypeEnum.NearestSecond, e.SignalTime) - stopwatchForRecalcStatistics.ElapsedMilliseconds;

        if (timeBuffer > 0)
            timerRecalcStatistics.Interval = timeBuffer;
        else
            timerRecalcStatistics.Interval = 1;

        stopwatchForRecalcStatistics.Reset();         
        timerRecalcStatistics.Enabled = true;
    }
 }

I wonder if it was lost from 1 to 120 ms in 1 second, because the processor is not as efficient as it could be with this implementation.

0
source

All Articles