C# 定時器 Timer 如何精確到 1-2 毫秒以內

wuty007發表於2024-09-01

最近在排查專案O他的一個問題,觸發了一毫秒或者2毫秒執行一次程序間通訊的,導致通訊阻塞的問題。這樣就需要用到模擬觸發1ms或者2ms觸發事件。這讓我第一時間想到了C#的定時器。由於我們專案用到的框架是基於.NETFramwork4.8的,所以我就建立了一個.NETFramwork4.8的WPF Demo 去驗證

 private Timer timer;

 private void TimerTest_OnClick(object sender, RoutedEventArgs e)
 {
     timer = new Timer();
     timer.Interval = 1;
     timer.Elapsed += Timer_Elapsed;
     timer.Start();
 }

 private void Timer_Elapsed(object? sender, ElapsedEventArgs e)
 {
     Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
 }

Demo很簡單, 就是建立一個按鈕,建立一個System.Timers.Timer,點選後執行,,但是執行結果,卻是要等待10+ms,跟我們設定的1ms的間隔不符合

於是乎我查閱了一番資料:c# - Thread.Sleep(1) 耗時超過 1ms_Stack Overflow中文網

其實這跟PC的時鐘相關,具體我就不解釋了,詳看上面連結的說明

我還不死心,會不會跟Dotnet的版本有關呢?

於是乎,我又建立了一個.Net8的 WPF的應用,用瞭如上一樣的程式碼,也是用到了 相同名稱空間的Timer

using Timer = System.Timers.Timer;

測試的結果,發現竟然可以精確到1-2ms的誤差之內

這應該是微軟對.Net8.0的 Timer 定時器做了最佳化了。

接下來如何在.NETFramwork4.8的環境下,實現精確度在1-2ms的定時執行了,只能自己寫一個自旋的定時器,透過判斷時間的間隔方式執行檢測。

private CancellationTokenSource tokenSource = new CancellationTokenSource();

private void SelfAutoTimer()
{
    Task.Run(() =>
    {
        var current = DateTime.Now;

        while (!tokenSource.IsCancellationRequested)
        {
            var temp = DateTime.Now;
            if ((temp - current).TotalMilliseconds >=1)
            {
                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
                current = temp;
            }
        }
    });
}

測試的結果跟.Net8.0的Timer的效果一樣的,精確度在1-2ms之內

接下來的專案應該都需要往.Net8裡邊遷移才行了,可以減少很多不必要的工作量。

相關文章