System.Threading.Tasks
是 .NET 中任务并行库(Task Parallel Library, TPL)的核心组件,它提供了基于任务的异步编程模型,是现代 .NET 并发编程的基础。
设计原理
1. 核心目标
抽象并发工作:将并发操作抽象为"任务"概念
资源高效利用:自动管理线程池资源
组合性:支持任务链式操作和组合
取消支持:内置取消操作机制
状态跟踪:提供任务生命周期管理
2. 关键组件
Task/Task<T>:表示异步操作的核心类
TaskScheduler:控制任务如何、何时被执行
TaskFactory:提供创建和启动任务的便捷方法
CancellationToken:任务取消机制
TaskCompletionSource:手动控制任务生命周期
3. 架构层次
用户层:开发者直接使用的Task API
调度层:TaskScheduler管理任务执行
线程池层:实际执行工作的底层线程池
典型用法示例
示例1:基础异步任务
// 创建并运行简单任务
Task.Run(() =>
{
Console.WriteLine("任务在后台线程执行");
Thread.Sleep(1000); // 模拟工作
Console.WriteLine("任务完成");
});
// 带返回值的任务
Task<int> calculateTask = Task.Run(() =>
{
Thread.Sleep(500);
return 42; // 计算结果
});
// 等待任务完成并获取结果
int result = await calculateTask;
Console.WriteLine($"计算结果: {result}");
应用场景:CPU密集型后台计算,不阻塞UI线程。
示例2:任务组合与延续
// 创建三个任务
Task<string> task1 = Task.Run(() => "Hello");
Task<string> task2 = Task.Run(() => "World");
Task<int> task3 = Task.Run(() => 2023);
// 等待所有任务完成
await Task.WhenAll(task1, task2, task3);
// 使用结果组合输出
Console.WriteLine($"{task1.Result} {task2.Result} {task3.Result}");
// 任务延续
Task continuation = task1.ContinueWith(t =>
{
Console.WriteLine($"前一个任务的结果: {t.Result}");
}, TaskContinuationOptions.OnlyOnRanToCompletion);
应用场景:并行执行多个独立操作,然后合并结果或执行后续操作。
示例3:高级任务控制
// 使用TaskCompletionSource手动控制任务
var tcs = new TaskCompletionSource<string>();
// 模拟异步回调
Timer timer = new Timer(_ =>
{
try
{
// 模拟工作
string result = DateTime.Now.ToString();
tcs.SetResult(result); // 手动完成任务
}
catch (Exception ex)
{
tcs.SetException(ex); // 手动设置异常
}
}, null, 1000, Timeout.Infinite);
// 等待任务完成
try
{
string timeString = await tcs.Task;
Console.WriteLine($"当前时间: {timeString}");
}
catch (Exception ex)
{
Console.WriteLine($"任务失败: {ex.Message}");
}
应用场景:将基于回调的异步API转换为基于任务的异步模式(TAP)。
示例4:取消任务
var cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
// 创建可取消的任务
Task longRunningTask = Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
token.ThrowIfCancellationRequested(); // 检查取消请求
Thread.Sleep(100); // 模拟工作
Console.WriteLine($"进度: {i}%");
}
}, token);
// 3秒后取消任务
cts.CancelAfter(3000);
try
{
await longRunningTask;
}
catch (OperationCanceledException)
{
Console.WriteLine("任务被取消");
}
应用场景:长时间运行的操作需要提供取消功能。
核心概念深入
1. 任务状态机
任务有以下几种状态:
Created
:已创建但未调度WaitingForActivation
:等待激活WaitingToRun
:已调度但未开始执行Running
:正在执行WaitingForChildrenToComplete
:等待子任务完成RanToCompletion
:成功完成Canceled
:被取消Faulted
:因异常失败
2. 任务调度策略
线程池调度器:默认调度器,使用线程池线程
同步上下文调度器:在特定同步上下文(如UI线程)执行
自定义调度器:可继承TaskScheduler实现特殊调度逻辑
3. 异常处理
任务中的异常会被捕获并存储在 Task.Exception
属性中,当等待任务或访问Result属性时,这些异常会被重新抛出。
Task faultyTask = Task.Run(() => throw new InvalidOperationException("出错了"));
try
{
await faultyTask;
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"捕获到异常: {ex.Message}");
}
最佳实践
避免Task.Wait和Task.Result:可能导致死锁,优先使用await
合理使用ConfigureAwait:库代码应使用ConfigureAwait(false)
注意任务生命周期:长时间运行的任务应考虑取消支持
避免过度并行化:太多并行任务会导致线程池饥饿
正确处理异常:确保所有任务异常都被处理
性能考虑
任务创建开销:轻量级但非零成本,高频场景考虑对象池
线程池压力:大量短任务可能导致线程池频繁调整
同步上下文:不必要地回到原始上下文会影响性能
System.Threading.Tasks
提供了强大而灵活的并发编程模型,是现代 .NET 应用程序中处理异步和并行操作的首选方式。