C#中System.Threading.Tasks庫的使用
System.Threading.Tasks 是 .NET 中任務(wù)并行庫(Task Parallel Library, TPL)的核心組件,它提供了基于任務(wù)的異步編程模型,是現(xiàn)代 .NET 并發(fā)編程的基礎(chǔ)。
設(shè)計(jì)原理
1. 核心目標(biāo)
抽象并發(fā)工作:將并發(fā)操作抽象為"任務(wù)"概念
資源高效利用:自動管理線程池資源
組合性:支持任務(wù)鏈?zhǔn)讲僮骱徒M合
取消支持:內(nèi)置取消操作機(jī)制
狀態(tài)跟蹤:提供任務(wù)生命周期管理
2. 關(guān)鍵組件
Task/Task<T>:表示異步操作的核心類
TaskScheduler:控制任務(wù)如何、何時被執(zhí)行
TaskFactory:提供創(chuàng)建和啟動任務(wù)的便捷方法
CancellationToken:任務(wù)取消機(jī)制
TaskCompletionSource:手動控制任務(wù)生命周期
3. 架構(gòu)層次
用戶層:開發(fā)者直接使用的Task API
調(diào)度層:TaskScheduler管理任務(wù)執(zhí)行
線程池層:實(shí)際執(zhí)行工作的底層線程池
典型用法示例
示例1:基礎(chǔ)異步任務(wù)
// 創(chuàng)建并運(yùn)行簡單任務(wù)
Task.Run(() =>
{
Console.WriteLine("任務(wù)在后臺線程執(zhí)行");
Thread.Sleep(1000); // 模擬工作
Console.WriteLine("任務(wù)完成");
});
// 帶返回值的任務(wù)
Task<int> calculateTask = Task.Run(() =>
{
Thread.Sleep(500);
return 42; // 計(jì)算結(jié)果
});
// 等待任務(wù)完成并獲取結(jié)果
int result = await calculateTask;
Console.WriteLine($"計(jì)算結(jié)果: {result}");應(yīng)用場景:CPU密集型后臺計(jì)算,不阻塞UI線程。
示例2:任務(wù)組合與延續(xù)
// 創(chuàng)建三個任務(wù)
Task<string> task1 = Task.Run(() => "Hello");
Task<string> task2 = Task.Run(() => "World");
Task<int> task3 = Task.Run(() => 2023);
// 等待所有任務(wù)完成
await Task.WhenAll(task1, task2, task3);
// 使用結(jié)果組合輸出
Console.WriteLine($"{task1.Result} {task2.Result} {task3.Result}");
// 任務(wù)延續(xù)
Task continuation = task1.ContinueWith(t =>
{
Console.WriteLine($"前一個任務(wù)的結(jié)果: {t.Result}");
}, TaskContinuationOptions.OnlyOnRanToCompletion);應(yīng)用場景:并行執(zhí)行多個獨(dú)立操作,然后合并結(jié)果或執(zhí)行后續(xù)操作。
示例3:高級任務(wù)控制
// 使用TaskCompletionSource手動控制任務(wù)
var tcs = new TaskCompletionSource<string>();
// 模擬異步回調(diào)
Timer timer = new Timer(_ =>
{
try
{
// 模擬工作
string result = DateTime.Now.ToString();
tcs.SetResult(result); // 手動完成任務(wù)
}
catch (Exception ex)
{
tcs.SetException(ex); // 手動設(shè)置異常
}
}, null, 1000, Timeout.Infinite);
// 等待任務(wù)完成
try
{
string timeString = await tcs.Task;
Console.WriteLine($"當(dāng)前時間: {timeString}");
}
catch (Exception ex)
{
Console.WriteLine($"任務(wù)失敗: {ex.Message}");
}應(yīng)用場景:將基于回調(diào)的異步API轉(zhuǎn)換為基于任務(wù)的異步模式(TAP)。
示例4:取消任務(wù)
var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
// 創(chuàng)建可取消的任務(wù)
Task longRunningTask = Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
token.ThrowIfCancellationRequested(); // 檢查取消請求
Thread.Sleep(100); // 模擬工作
Console.WriteLine($"進(jìn)度: {i}%");
}
}, token);
// 3秒后取消任務(wù)
cts.CancelAfter(3000);
try
{
await longRunningTask;
}
catch (OperationCanceledException)
{
Console.WriteLine("任務(wù)被取消");
}應(yīng)用場景:長時間運(yùn)行的操作需要提供取消功能。
核心概念深入
1. 任務(wù)狀態(tài)機(jī)
任務(wù)有以下幾種狀態(tài):
Created:已創(chuàng)建但未調(diào)度WaitingForActivation:等待激活WaitingToRun:已調(diào)度但未開始執(zhí)行Running:正在執(zhí)行WaitingForChildrenToComplete:等待子任務(wù)完成RanToCompletion:成功完成Canceled:被取消Faulted:因異常失敗
2. 任務(wù)調(diào)度策略
線程池調(diào)度器:默認(rèn)調(diào)度器,使用線程池線程
同步上下文調(diào)度器:在特定同步上下文(如UI線程)執(zhí)行
自定義調(diào)度器:可繼承TaskScheduler實(shí)現(xiàn)特殊調(diào)度邏輯
3. 異常處理
任務(wù)中的異常會被捕獲并存儲在 Task.Exception 屬性中,當(dāng)?shù)却蝿?wù)或訪問Result屬性時,這些異常會被重新拋出。
Task faultyTask = Task.Run(() => throw new InvalidOperationException("出錯了"));
try
{
await faultyTask;
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"捕獲到異常: {ex.Message}");
}最佳實(shí)踐
避免Task.Wait和Task.Result:可能導(dǎo)致死鎖,優(yōu)先使用await
合理使用ConfigureAwait:庫代碼應(yīng)使用ConfigureAwait(false)
注意任務(wù)生命周期:長時間運(yùn)行的任務(wù)應(yīng)考慮取消支持
避免過度并行化:太多并行任務(wù)會導(dǎo)致線程池饑餓
正確處理異常:確保所有任務(wù)異常都被處理
性能考慮
任務(wù)創(chuàng)建開銷:輕量級但非零成本,高頻場景考慮對象池
線程池壓力:大量短任務(wù)可能導(dǎo)致線程池頻繁調(diào)整
同步上下文:不必要地回到原始上下文會影響性能
System.Threading.Tasks 提供了強(qiáng)大而靈活的并發(fā)編程模型,是現(xiàn)代 .NET 應(yīng)用程序中處理異步和并行操作的首選方式。
到此這篇關(guān)于C#中System.Threading.Tasks庫的使用的文章就介紹到這了,更多相關(guān)C# System.Threading.Tasks內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實(shí)現(xiàn)PDF合并的項(xiàng)目實(shí)踐
有時我們可能會遇到需要的資料或教程被分成了幾部分存放在多個PDF文件中,本文主要介紹了C#實(shí)現(xiàn)PDF合并的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01

