首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET 三大計時器類別深度對比與線程安全實戰

     編輯:關於.NET

前言

無論客戶端應用還是伺服器組件,計時器都是關鍵角色。編寫高效的計時器驅動代碼,需要清晰理解程序流程與 .NET 線程模型。.NET Framework 提供三種計時器:

  • System.Windows.Forms.Timer(UI 線程)
  • System.Timers.Timer(伺服器/工作者線程)
  • System.Threading.Timer(高階/線程池)

前兩者出現在 VS 工具箱,最後一個僅程式碼使用。選錯類別將導致嚴重效能或正確性問題。

System.Windows.Forms.Timer:UI 線程計時器

特性:事件在 UI 線程同步引發,不會搶佔 正在執行的代碼(除非呼叫 Application.DoEvents)。UI 線程同時負責處理視窗訊息佇列。

行為驗證

間隔 1000ms,點擊 Start → Sleep(5秒) → Stop,輸出:

Timer Event 1 @ 4:09:29 on Thread: UIThread
Timer Event 2 @ 4:09:30 on Thread: UIThread
Timer Event 3 @ 4:09:31 on Thread: UIThread
Sleeping for 5000 ms...
Timer Event 4 @ 4:09:36 on Thread: UIThread  <-- 睡眠期間事件丟失,無排隊

UI 線程睡眠時計時器掛起,喚醒後不補發遺漏事件。

編程介面

var tmr = new System.Windows.Forms.Timer();
tmr.Interval = 1000; // 約 55ms 精度
tmr.Tick += (s,e) => { /* UI 線程執行 */ };
tmr.Start();

System.Timers.Timer:伺服器計時器

特性:預設在 CLR 線程池工作者線程 引發 Elapsed 事件,支援多線程安全訪問。提供 SynchronizingObject 屬性強制事件在指定物件建立線程(如 UI 線程)執行。

行為驗證

相同測試,輸出:

Timer Event 4 @ 4:09:36 on Thread: WorkerThread
Timer Event 5 @ 4:09:37 on Thread: WorkerThread
...
Timer Event 8 @ 4:09:40 on Thread: WorkerThread  <-- 睡眠期間事件排隊,喚醒後批次處理

不會跳過任何事件,即使 UI 線程忙碌。

關鍵屬性

  • AutoReset:是否重複觸發
  • Interval 修改會重置計數器
  • ElapsedEventArgs.SignalTime:精確觸發時間,配合 Stop() 判斷競態

同步到 UI 線程

tmr.SynchronizingObject = this; // 表單或控件
// 內部使用 SynchronizingObject.BeginInvoke 排程

System.Threading.Timer:高階輕量計時器

特性:不在工具箱,介面較複雜,非天生線程安全(但可安全使用)。四個建構函數重載:

public Timer(TimerCallback callback, object state, long dueTime, long period);
// dueTime: 首次觸發延遲 (0=立即, Timeout.Infinite=不啟動)
// period: 間隔 (0/Timeout.Infinite=單次)

TimerCallback 簽名:void TimerCallback(object state),在工作者線程執行,需自行保證 state 線程安全。

動態調整

tmr.Change(0, 1000);           // 啟動
tmr.Change(Timeout.Infinite, Timeout.Infinite); // 停止

行為同 System.Timers.Timer:工作者線程觸發,事件排隊不丟失。

UI 交互必須手動封送

control.Invoke((Action)(() => { /* UI 代碼 */ }));

線程安全編程模式

統一事件處理

private delegate void ShowTimerEventFiredDelegate(DateTime time, string threadName);

private void ShowTimerEventFired(DateTime time, string threadName)
{
    if (listBox.InvokeRequired)
        listBox.BeginInvoke(new ShowTimerEventFiredDelegate(ShowTimerEventFired), time, threadName);
    else
        listBox.Items.Add($"{time} on {threadName}");
}

重入保護

若事件處理耗時超過間隔,會並發執行導致狀態損壞。解決方案:

private void tmr_Elapsed(object sender, ElapsedEventArgs e)
{
    tmr.Enabled = false; // 暫停
    try {
        Interlocked.Increment(ref counter);
        Thread.Sleep(5000);
        MessageBox.Show(counter.ToString());
    } finally {
        tmr.Enabled = true; // 恢復
    }
}

或使用 Monitor/Mutex 排隊。

三大計時器快速對照表

特性Forms.TimerTimers.TimerThreading.Timer
觸發線程UI 線程工作者線程工作者線程
事件排隊否(丟失)是是
UI 同步支援原生SynchronizingObject手動 Invoke
精度~55ms高高
適用場景簡單 UI 動畫伺服器/需同步 UI高效能/輕量/無 UI

選型建議:能用 Windows 排程器執行獨立程式解決問題時,優先考慮更簡單的方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved