iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0

任務狀態流轉與延續

延續儲存在 m_continuationObject 中,可能型別包括:

  1. 單一動作委派(Action<object?>)
  2. 延續清單(List)
  3. 特殊型別(用於同步執行最小化開銷的 sentinel)

以下是流程簡單的描述

狀態:Task 完成(Completed)
 → 觸發延續處理
  → 呼叫 Task.FinishContinuations()
   → 取出 m_continuationObject
    → 延續型別判斷:
     → 單一委派:直接排程或內聯呼叫
     → 清單型別:逐一排程/呼叫
     → 特殊型別:依邏輯處理
     → 排程至執行環境:
       → 若有 SynchronizationContext 且未設定 ConfigureAwait(false):使用 Post
       → 否則:使用預設 TaskScheduler(ThreadPool)

關鍵原始碼點:

  • Task.AddCompletionAction
  • Task.FinishContinuations
  • TaskAwaiter.OnCompleted / UnsafeOnCompleted

延續排程策略:

  • 當設定 ConfigureAwait(true) 時,使用 SynchronizationContext.Post 返還至原邏輯上下文
  • 預設使用 TaskScheduler,由 ThreadPool 執行
  • UnsafeOnCompleted 避免捕捉執行環境,適用於可信內部路徑

TaskScheduler 與 ThreadPool

TaskScheduler 負責決定延續執行位置,預設實作為 ThreadPoolTaskScheduler,將工作排入 ThreadPool。

以下是流程簡單的描述

狀態:建立 Task (Created)
 → 呼叫 Task.ScheduleAndStart
  → 交由 TaskScheduler.QueueTask
   → ThreadPool.UnsafeQueueCustomWorkItem
     → 放入執行緒本地佇列(Work-Stealing)
       → Worker 執行 TryExecuteTaskInline
         → 進入執行狀態

ThreadPool 核心結構:

  • 全域 FIFO 佇列
  • 每執行緒本地 LIFO 佇列(推入時從頂端、竊取時從尾端)
  • Hill Climbing 演算法動態調整工作執行緒數量
  • 透過 IThreadPoolWorkItem 介面包裝工作項

關鍵原始碼觀察點:

  • PortableThreadPool.WorkerThread.WorkerThreadStart
  • ThreadPoolWorkQueue.Dequeue
  • 飢餓偵測:監控佇列長度與進度(可搭配 dotnet-counters 工具)

SynchronizationContext 與 ExecutionContext

名稱 職責 典型來源 影響
SynchronizationContext 特定框架邏輯上下文返還 WPF、WinForms、舊版 ASP.NET 控制 await 執行位置
ExecutionContext 安全性、AsyncLocal、文化設定傳遞 CLR 執行層 影響延續成本與呼叫鏈

降低成本策略:

  • 可信內部路徑使用 UnsafeOnCompleted
  • Task.Run 內部啟用 ExecutionContext.SuppressFlow(需謹慎評估安全性)

ValueTask 與 IValueTaskSource

動機:消除已同步完成 Task 的物件配置開銷,降低 GC 壓力。

ValueTask 包裝型別:

  1. 直接結果(T result)
  2. Task(退化模式)
  3. IValueTaskSource + token(高階重用來源)

使用要點:

  • 僅適用高頻操作(≥90% 同步完成率)
  • 單次使用限制:重複 await 需轉為 Task(AsTask())
  • 公用 API 應保守採用,避免呼叫端誤用
  • 低頻操作改用 ValueTask 無實質效益

Async Method Builder 差異

AsyncTaskMethodBuilder 與 AsyncValueTaskMethodBuilder 共同功能:

  • 延遲建立底層物件(同步完成路徑)
  • 封裝 SetResult / SetException 等 API

ValueTask Builder 優化:同步完成時直接生成 ValueTask,避免 Task 配置。


ConfigureAwait 與上下文捕捉策略

模式 行為 適用場景
預設 捕捉 SynchronizationContext 與 ExecutionContext UI 層、需回原邏輯上下文
ConfigureAwait(false) 僅捕捉 ExecutionContext 函式庫、後端服務
ConfigureAwait(ForceYield) (.NET 9+) 完成後仍強制排程 測試、避免深遞迴堆疊
使用 Unsafe Awaiter 不捕捉 ExecutionContext 高性能內部路徑

原始碼實作:ConfiguredTaskAwaitable.ConfiguredTaskAwaiter 決定排程策略。


取消機制

Task 需主動觀察取消權杖:

  1. 傳遞至支援取消的 API
  2. 手動呼叫 token.ThrowIfCancellationRequested()
  3. 透過 TaskCompletionSource.TrySetCanceled 標記為 Canceled

await 已取消 Task 時,拋出含權杖的 OperationCanceledException。


上一篇
Task 內部結構
下一篇
效能策略
系列文
新 .NET & Azure & IoT & AI 開源技術實戰手冊 (含深入官方程式碼講解) 22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言