最近在排查專案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裡邊遷移才行了,可以減少很多不必要的工作量。