在現代 C# 開發中,如何有效執行背景任務、限制併發數量、與 UI 協作已成為必備技能。本篇文章整理各種方式的特性、應用場景,並附上實用程式碼範例。
🧩 為何需要多種背景任務執行方式?
背景任務可避免 UI 卡頓、提升效能並允許多工操作。常見需求包括:
- 執行不阻塞主線程(UI)
- 控制同時併發的數量
- 可 await 等待完成
- 與 WinForms / WPF UI 結合
✅ 背景任務方式比較(含執行類型)
技術 | 控制併發數 | 支援 async/await | 適用場景 | UI 支援 | 執行方式 |
---|---|---|---|---|---|
BackgroundWorker | ❌ | ❌ | 舊式 WinForms/WPF 背景任務 | ✅ | Thread |
ThreadPool | ❌ | ❌ | 快速提交背景任務 | ❌ | Thread |
Task / Task.Run | ❌ | ✅ | 一般非同步任務 | ❌ | Thread |
Task + SemaphoreSlim | ✅ | ✅ | 控制併發數、IO 密集任務 | ❌ | Thread + Coroutine |
Parallel.ForEach | ✅ | ❌ | CPU 密集型處理 | ❌ | Thread |
TPL Dataflow | ✅ | ✅ | 複雜資料管線與佇列 | ❌ | Thread |
async/await | ✅(手動限制) | ✅ | 非同步 API / DB / IO 流程 | ❌ | Coroutine |
🧪 範例程式碼
1️⃣ BackgroundWorker
var worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
Thread.Sleep(2000);
e.Result = "任務完成";
};
worker.RunWorkerCompleted += (s, e) =>
{
MessageBox.Show((string)e.Result);
};
worker.RunWorkerAsync();
2️⃣ ThreadPool
ThreadPool.QueueUserWorkItem(state =>
{
Console.WriteLine("背景任務開始");
Thread.Sleep(1000);
Console.WriteLine("任務完成");
});
3️⃣ Task / Task.Run
await Task.Run(() =>
{
Thread.Sleep(1000);
Console.WriteLine("Task 執行完成");
});
4️⃣ Task + SemaphoreSlim(控制併發數)
var semaphore = new SemaphoreSlim(3);
var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
int index = i;
tasks.Add(Task.Run(async () =>
{
await semaphore.WaitAsync();
try
{
Console.WriteLine($"工作 {index} 開始");
await Task.Delay(2000);
Console.WriteLine($"工作 {index} 結束");
}
finally
{
semaphore.Release();
}
}));
}
await Task.WhenAll(tasks);
5️⃣ Parallel.ForEach
Parallel.ForEach(Enumerable.Range(0, 5), i =>
{
Console.WriteLine($"執行任務 {i} - 線程 {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
});
6️⃣ TPL Dataflow
var block = new ActionBlock<int>(async i =>
{
Console.WriteLine($"處理 {i}");
await Task.Delay(500);
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 3
});
foreach (var i in Enumerable.Range(0, 10))
{
block.Post(i);
}
block.Complete();
await block.Completion;
📦 需安裝: System.Threading.Tasks.Dataflow
7️⃣ async/await Coroutine
async Task<string> DownloadAsync(string url)
{
using var client = new HttpClient();
var result = await client.GetStringAsync(url);
return result;
}
var html = await DownloadAsync("https://example.com");
Console.WriteLine(html);
🧠 Thread vs Coroutine
類型 | 說明 |
---|---|
Thread | 作業系統層級,適合同步或 CPU 密集任務 |
Coroutine | 由 .NET 控制流程(Task + await),讓出執行緒等 IO |
💡 小結
- ✅
Task
與async/await
是現代開發主力 - ✅
SemaphoreSlim
控制併發數 - ⚠️
BackgroundWorker
僅建議用於舊 UI 專案
沒有留言:
張貼留言