Task 是 .NET 任務平行庫 (TPL) 的核心抽象,代表「未來會完成的工作」。在 Windows 8 Store Apps 中,Task 基於線程池,取代傳統 Thread 成為非同步與平行運算的基石。本文系統介紹 Task 建立、取消、續作、多任務協調與 Parallel 平行運算。
// 1. Task.Run:建立並立即排程(推薦)
var task1 = Task.Run(() => DoWork());
// 2. Task.Factory.StartNew:進階選項(長時間任務指定 LongRunning)
var task2 = Task.Factory.StartNew(() => DoWork(), TaskCreationOptions.LongRunning);
// 3. new Task() + Start():分離建立與啟動(罕見需求)
var task3 = new Task(() => DoWork());
task3.Start();
// 4. TaskCompletionSource:手動控制完成狀態(包裝舊 API)
var tcs = new TaskCompletionSource();
// ... 非同步操作完成時 tcs.SetResult(42) 或 tcs.SetException(ex)
Task task4 = tcs.Task;
var cts = new CancellationTokenSource();
var token = cts.Token;
var task = Task.Run(() => {
for (int i = 0; i < 100; i++) {
token.ThrowIfCancellationRequested(); // 拋出 OperationCanceledException
Thread.Sleep(100);
}
}, token);
// 外部請求取消
cts.Cancel(); // 或 cts.CancelAfter(3000);
// 等待並處理取消
try {
await task;
} catch (OperationCanceledException) when (token.IsCancellationRequested) {
// 正常取消,不視為錯誤
}
ContinueWith 是底層續作 API,await 是語法糖(編譯器自動生成續作)。現代代碼優先使用 await:
// 現代風格
var result = await Task.Run(() => Compute());
UpdateUI(result);
// 續作風格(需手動切 UI 線程)
Task.Run(() => Compute())
.ContinueWith(t => Dispatcher.RunAsync(..., () => UpdateUI(t.Result)));
ContinueWith 進階選項: TaskContinuationOptions.OnlyOnRanToCompletion、OnlyOnFaulted、OnlyOnCanceled、ExecuteSynchronously 等。
| 方法 | 行為 | 返回值 | 典型用途 |
|---|---|---|---|
| Task.WhenAll | 非阻塞等待全部完成 | Task / Task[] | 並行啟動多個獨立操作,全部完成後聚合結果 |
| Task.WhenAny | 非阻塞等待任一完成 | Task | 超時控制、競速模式、第一個響應者獲勝 |
| Task.WaitAll | 同步阻塞等待全部 | void | 僅用於非 UI 線程、Main 方法等同步語境 |
| Task.WaitAny | 同步阻塞等待任一 | int (索引) | 同步語境下的競速等待 |
// 並行下載多個 URL,全部完成後處理
var downloadTasks = urls.Select(url => httpClient.GetStringAsync(url)).ToArray();
string[] results = await Task.WhenAll(downloadTasks);
// 競速:3 秒內未完成則取消
var timeoutTask = Task.Delay(3000);
var completedTask = await Task.WhenAny(longRunningTask, timeoutTask);
if (completedTask == timeoutTask) cts.Cancel();
Parallel 提供高層平行迴圈與調用,自動處理分區、負載平衡、線程池調度:
// 平行迴圈
Parallel.For(0, 1000, i => {
ProcessItem(i);
});
// 平行 foreach(支援 Partitioner 自訂分區)
Parallel.ForEach(largeCollection, item => {
ProcessItem(item);
});
// 區域變數避免共享狀態爭用
Parallel.For(0, n,
() => 0, // 區域初始化
(i, state, local) => local + Compute(i), // 區域累加
local => Interlocked.Add(ref total, local) // 合併
);
// 平行執行多個獨立 Action
Parallel.Invoke(
() => Task1(),
() => Task2(),
() => Task3()
);
var options = new ParallelOptions {
MaxDegreeOfParallelism = 4, // 限制最大並行度
CancellationToken = cts.Token, // 支援取消
TaskScheduler = customScheduler // 自訂調度器
};
Parallel.ForEach(collection, options, item => { ... });
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 非同步 I/O 操作 | Task / await | 釋放線程、可擴展性最強 |
| CPU 密集型批次處理 | Parallel.ForEach | 自動分區、負載平衡、簡潔聲明式 |
| 固定數量獨立非同步操作 | Task.WhenAll | 語意清晰、結果聚合自然 |
| 動態數量、需取消、超時控制 | Task + CancellationToken | 精細控制、組合靈活 |
| 需自訂分區、負載平衡策略 | Parallel + Partitioner | 框架級支援 |
await。Task.Run(async () => await ...) 而非 Task.Run(async () => { await ... }) 後者編譯為 async void,例外無法捕獲。SemaphoreSlim 限流 + Task.WhenAll。token,內部定期 ThrowIfCancellationRequested。Task.WhenAll 會拋出 AggregateException(包含所有例外),await 只拋出第一個。熟練掌握 Task 與 Parallel 的協作模式,能讓 Windows 8 Store Apps 在保持 UI 流暢的同時,充分發揮多核心 CPU 的計算能力。