1. TaskCompletionSource核心机制解析
TaskCompletionSource(简称TCS)是.NET异步编程模型中的关键组件,它本质上是一个任务控制器,允许开发者手动控制Task的生命周期状态。与常规async/await生成的Task不同,TCS提供了对任务状态的完全掌控权。
1.1 核心工作原理
TCS通过内部维护的状态机实现任务控制,其核心机制包含三个要素:
- 任务绑定:每个TCS实例关联一个不可变的Task对象
- 状态转换:通过SetResult/SetException等方法改变任务状态
- 同步控制:确保状态变更的线程安全性
典型的工作流程如下:
csharp复制var tcs = new TaskCompletionSource<bool>();
// 后台操作完成后
ThreadPool.QueueUserWorkItem(_ => {
try {
// 模拟耗时操作
Thread.Sleep(1000);
tcs.SetResult(true); // 状态变为RanToCompletion
} catch(Exception ex) {
tcs.SetException(ex); // 状态变为Faulted
}
});
return tcs.Task; // 返回关联的Task
1.2 与普通Task的对比
| 特性 | 常规async Task | TaskCompletionSource |
|---|---|---|
| 状态控制 | 编译器自动管理 | 手动控制 |
| 适用场景 | 线性异步逻辑 | 事件/回调驱动 |
| 异常传播 | 自动捕获 | 需手动设置 |
| 取消支持 | 通过CancellationToken | 需自行实现 |
| 性能开销 | 较高 | 较低 |
2. 关键API深度剖析
2.1 状态控制方法
TCS提供四种核心状态变更方法:
-
SetResult:标记任务成功完成
- 触发Task的IsCompleted状态
- 执行所有已注册的ContinueWith回调
- 注意:只能调用一次,重复调用会抛出异常
-
SetException:标记任务失败
- 异常信息会包装在AggregateException中
- 典型使用模式:
csharp复制try { // 业务逻辑 } catch (Exception ex) { tcs.SetException(ex); }
-
SetCanceled:标记任务取消
- 与CancellationToken配合使用
- 会使Task的Status变为Canceled
-
TrySet*变体:
- TrySetResult/ TrySetException/ TrySetCanceled
- 线程安全的状态变更方法
- 返回bool表示操作是否成功
2.2 高级控制技巧
状态变更的线程安全实现:
csharp复制// 正确做法
if (!tcs.TrySetResult(value))
{
// 处理状态已变更的情况
}
// 错误做法(可能引发异常)
tcs.SetResult(value);
取消功能集成示例:
csharp复制public static Task<T> WithCancellation<T>(
this Task<T> task, CancellationToken ct)
{
var tcs = new TaskCompletionSource<T>();
ct.Register(() => tcs.TrySetCanceled());
task.ContinueWith(t => {
if (t.IsFaulted) tcs.TrySetException(t.Exception);
else if (t.IsCanceled) tcs.TrySetCanceled();
else tcs.TrySetResult(t.Result);
}, TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
3. 典型应用场景实战
3.1 事件驱动编程转换
将传统事件模式转换为Task模式:
csharp复制public static Task<byte[]> DownloadDataAsync(string url)
{
var tcs = new TaskCompletionSource<byte[]>();
var client = new WebClient();
client.DownloadDataCompleted += (s, e) => {
if (e.Error != null) tcs.TrySetException(e.Error);
else if (e.Cancelled) tcs.TrySetCanceled();
else tcs.TrySetResult(e.Result);
};
client.DownloadDataAsync(new Uri(url));
return tcs.Task;
}
3.2 超时控制实现
csharp复制public static async Task<T> WithTimeout<T>(
this Task<T> task, TimeSpan timeout)
{
var tcs = new TaskCompletionSource<T>();
var timer = new Timer(_ =>
tcs.TrySetException(new TimeoutException()),
null, timeout, Timeout.InfiniteTimeSpan);
task.ContinueWith(t => {
timer.Dispose();
if (t.IsFaulted) tcs.TrySetException(t.Exception);
else if (t.IsCanceled) tcs.TrySetCanceled();
else tcs.TrySetResult(t.Result);
});
return await tcs.Task;
}
3.3 多任务协调
csharp复制public static Task<T[]> WhenAll<T>(params Task<T>[] tasks)
{
var tcs = new TaskCompletionSource<T[]>();
var results = new T[tasks.Length];
var remaining = tasks.Length;
for (int i = 0; i < tasks.Length; i++)
{
tasks[i].ContinueWith(t => {
if (t.IsFaulted)
tcs.TrySetException(t.Exception);
else if (t.IsCanceled)
tcs.TrySetCanceled();
else
{
results[i] = t.Result;
if (Interlocked.Decrement(ref remaining) == 0)
tcs.TrySetResult(results);
}
});
}
return tcs.Task;
}
4. 性能优化与陷阱规避
4.1 内存优化技巧
-
对象池模式:
csharp复制private static readonly ObjectPool<TaskCompletionSource<bool>> s_pool = ObjectPool.Create<TaskCompletionSource<bool>>(); public static Task CreatePooledTask() { var tcs = s_pool.Get(); return tcs.Task.ContinueWith(t => { s_pool.Return(tcs); return t.Result; }); } -
ValueTask集成:
csharp复制public ValueTask<int> OptimizedMethod() { if (_cacheAvailable) return new ValueTask<int>(42); var tcs = new TaskCompletionSource<int>(); // 异步操作... return new ValueTask<int>(tcs.Task); }
4.2 常见陷阱及解决方案
陷阱1:状态重复设置
csharp复制// 错误示例
tcs.SetResult(1);
tcs.SetResult(2); // 抛出InvalidOperationException
// 正确做法
if (!tcs.TrySetResult(1))
{
// 处理状态已变更的情况
}
陷阱2:未处理的异常
csharp复制// 危险代码
void EventHandler(object sender, EventArgs e)
{
tcs.SetResult(GetResult());
}
// 安全版本
void EventHandler(object sender, EventArgs e)
{
try {
tcs.TrySetResult(GetResult());
} catch(Exception ex) {
tcs.TrySetException(ex);
}
}
陷阱3:上下文丢失
csharp复制// 可能丢失同步上下文
Task.Run(() => tcs.SetResult(42));
// 保持上下文
var context = SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(_ => {
try {
var result = Compute();
context.Post(_ => tcs.SetResult(result), null);
} catch(Exception ex) {
context.Post(_ => tcs.SetException(ex), null);
}
});
5. 高级模式与最佳实践
5.1 自定义Awaitable模式
csharp复制public struct CustomAwaitable
{
private readonly TaskCompletionSource<bool> _tcs;
public CustomAwaitable() => _tcs = new TaskCompletionSource<bool>();
public CustomAwaiter GetAwaiter() => new CustomAwaiter(_tcs);
public struct CustomAwaiter : INotifyCompletion
{
private readonly TaskCompletionSource<bool> _tcs;
public bool IsCompleted => _tcs.Task.IsCompleted;
public void OnCompleted(Action continuation) =>
_tcs.Task.ContinueWith(_ => continuation());
public bool GetResult() => _tcs.Task.Result;
}
public void Complete() => _tcs.SetResult(true);
}
5.2 与IAsyncDisposable集成
csharp复制public class AsyncResource : IAsyncDisposable
{
private readonly TaskCompletionSource<bool> _disposeTcs = new();
public async ValueTask DisposeAsync()
{
await _disposeTcs.Task;
// 实际清理逻辑
}
public void Release() => _disposeTcs.TrySetResult(true);
}
5.3 诊断增强实现
csharp复制public class DiagnosticTaskCompletionSource<T> : TaskCompletionSource<T>
{
private readonly StackTrace _creationStack;
public DiagnosticTaskCompletionSource() =>
_creationStack = new StackTrace(1, true);
public string GetCreationStackTrace() =>
_creationStack.ToString();
public bool TrySetResult(T result)
{
if (!base.TrySetResult(result))
{
Debug.WriteLine($"SetResult failed. Created at:\n{_creationStack}");
return false;
}
return true;
}
}
