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

Windows 8 Store Apps 線程池完整指南:ThreadPoolTimer 延遲/週期執行與 ThreadPool 工作項佇列

     編輯:關於.NET

前言

Windows Runtime 提供現代化線程池 API(Windows.System.Threading 命名空間),取代傳統 System.Threading.ThreadPool。核心類別 ThreadPoolTimer 處理時間觸發工作,ThreadPool 處理佇列工作項。本文詳細解析延遲執行、週期執行、工作項提交與取消機制。

ThreadPoolTimer:時間驅動的工作排程

延遲執行:CreateTimer

單次觸發,指定延遲時間後執行委派:

var timer = ThreadPoolTimer.CreateTimer(
    handler: (timer) => {
        // 執行於線程池線程
        var result = ComputeHeavy();
        // 需更新 UI 時切回 UI 線程
        Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
            lblResult.Text = result;
        });
    },
    delay: TimeSpan.FromSeconds(3), // 3 秒後觸發
    destroyed: (timer) => {
        // 計時器銷毀回呼(完成或取消時觸發)
        Debug.WriteLine("Timer completed");
    }
);

// 取消尚未觸發的計時器
timer.Cancel();

週期執行:CreatePeriodicTimer

固定間隔重複執行,不保證精確間隔(若上次執行未完成,下次仍會嘗試啟動新線程):

int count = 0;
var periodicTimer = ThreadPoolTimer.CreatePeriodicTimer(
    handler: (timer) => {
        count++;
        Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
            lblCount.Text = $"執行次數: {count}";
        });
    },
    period: TimeSpan.FromMilliseconds(100), // 每 100ms 嘗試執行
    destroyed: (timer) => {
        Debug.WriteLine("Periodic timer destroyed");
    }
);

// 停止週期執行
periodicTimer.Cancel();

關鍵特性:

  • Delay/Period 唯讀屬性可檢視設定值
  • 處理函數在線程池執行,嚴禁阻塞長時間運算,否則影響其他佇列工作
  • UI 更新必須透過 Dispatcher 或 SynchronizationContext 切回 UI 線程

ThreadPool:佇列工作項執行

RunAsync:提交工作至線程池

var workItem = ThreadPool.RunAsync(
    handler: (workItem) => {
        // 此處在線程池線程執行
        for (int i = 0; i <= 100; i++) {
            // 支援取消檢查
            if (workItem.Status == AsyncStatus.Canceled) break;
            
            Thread.Sleep(50); // 模擬工作
            
            // 回報進度(需切 UI 線程)
            Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
                progressBar.Value = i;
            });
        }
    },
    priority: WorkItemPriority.High // Low/Normal/High
);

// 完成事件訂閱
workItem.Completed = async (action, status) => {
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
        switch (status) {
            case AsyncStatus.Completed: lblStatus.Text = "完成"; break;
            case AsyncStatus.Canceled: lblStatus.Text = "已取消"; break;
            case AsyncStatus.Error: lblStatus.Text = "錯誤"; break;
        }
    });
};

// 取消工作項
workItem.Cancel();

優先級與調度

WorkItemPriority 影響線程池調度順序:

  • High: 緊急、短時間工作(如用戶交互回應)
  • Normal: 一般背景工作(預設)
  • Low: 非即時、可延遲工作(如快取預熱、日誌寫入)

進階:以 async/await 簡化 ThreadPool 使用

ThreadPool.RunAsync 返回 IAsyncAction,可直接 await:

private async void btnAwaitDemo_Click(object sender, RoutedEventArgs e) {
    lblStatus.Text = "執行中...";
    
    string result = await ThreadPool.RunAsync(async (workItem) => {
        await Task.Delay(3000); // 非阻塞等待
        return "線程池工作完成,已自動切回 UI 線程";
    }).AsTask(); // 轉為 Task 以支援 await
    
    lblStatus.Text = result;
}

注意: IAsyncAction 不直接支援 await,需 .AsTask() 轉換(參考前文互轉技術)。

ThreadPoolTimer vs ThreadPool 選擇指南

維度ThreadPoolTimerThreadPool.RunAsync
觸發方式時間驅動(延遲/週期)立即佇列/手動觸發
適用場景定時輪詢、週期性檢查、延遲初始化背景計算、I/O 操作、長時間任務
取消機制Timer.Cancel()IAsyncAction.Cancel() + 狀態檢查
精確度約略(受線程池擁塞影響)立即排程,無時間保證
重複執行內建 PeriodicTimer需自行實作循環/遞歸

最佳實踐與避坑

  1. 工作項保持短小: 線程池線程為共享資源,長時間運算請用 Task.Run + TaskCreationOptions.LongRunning 或自建線程。
  2. 定期檢查取消狀態: workItem.Status == AsyncStatus.Canceled,避免資源浪費。
  3. UI 更新切換內文: 統一使用 Dispatcher.RunAsync,避免跨線程存取 UI 元素例外。
  4. 避免在 Timer 處理函數中阻塞: 週期計時器若處理超過間隔,會導致佇列堆積,改用 Task.Delay 循環模式。
  5. 正確釋放: 頁面離開時 Cancel() 所有計時器與工作項,防止記憶體洩漏與存取已釋放 UI 元素。
  6. 優先級合理使用: 濫用 High 會導致真正緊急工作被擠壓。

與傳統 ThreadPool 對比

Windows.System.Threading.ThreadPool 為 WinRT 原生 API,返回 IAsyncAction,整合 WinRT 取消/進度/完成模型;System.Threading.ThreadPool 為 .NET 傳統 API,返回 Task,整合 TPL 體系。Windows 8 Store Apps 推薦使用 WinRT 版本,確保與系統資源管理一致。

善用線程池 API,能讓應用程式在保持 UI 高回應性的同時,高效處理背景工作負載。

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