UniTask源码解析:UniTaskCompletionSource与结果设置
在Unity开发中,异步编程是提升性能和用户体验的关键技术。UniTask作为Unity生态中高效的异步编程库,通过UniTaskCompletionSource提供了灵活的异步结果控制机制。本文将深入解析UniTaskCompletionSource的实现原理与结果设置逻辑,帮助开发者更好地理解和使用这一核心组件。
UniTaskCompletionSource的核心架构
UniTaskCompletionSource位于src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskCompletionSource.cs文件中,是实现异步操作结果控制的核心类。它提供了三种基本状态转换能力:
- 设置成功结果:通过
TrySetResult方法完成 - 设置取消状态:通过
TrySetCanceled方法完成 - 设置异常状态:通过
TrySetException方法完成
接口设计与状态管理
该类实现了IPromise接口组合,包含三个关键接口:
public interface IPromise : IResolvePromise, IRejectPromise, ICancelPromise { }
其中:
IResolvePromise提供TrySetResult()方法IRejectPromise提供TrySetException(Exception)方法ICancelPromise提供TrySetCanceled(CancellationToken)方法
状态管理通过intStatus字段实现,使用UniTaskStatus枚举表示当前异步操作状态:
int intStatus; // 存储UniTaskStatus枚举值
核心实现解析:UniTaskCompletionSourceCore
UniTaskCompletionSourceCore<T>是泛型状态管理核心结构体,负责:
- 存储异步操作结果或错误信息
- 管理延续回调(continuation)
- 处理多线程并发访问
结果设置的原子操作
以TrySetResult方法为例,其实现采用了原子操作确保线程安全:
public bool TrySetResult(TResult result)
{
if (Interlocked.Increment(ref completedCount) == 1)
{
this.result = result;
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
{
continuation(continuationState);
}
return true;
}
return false;
}
关键实现细节:
- 使用
Interlocked.Increment确保只有一个线程能成功设置结果 - 通过
s_sentinel哨兵对象处理延续回调的竞态条件 - 完成后立即调用已注册的延续回调
异常处理机制
异常处理通过ExceptionHolder类实现,确保异常信息正确传递并避免内存泄漏:
internal class ExceptionHolder
{
ExceptionDispatchInfo exception;
bool calledGet = false;
public ExceptionDispatchInfo GetException()
{
if (!calledGet)
{
calledGet = true;
GC.SuppressFinalize(this);
}
return exception;
}
~ExceptionHolder()
{
if (!calledGet)
{
UniTaskScheduler.PublishUnobservedTaskException(exception.SourceException);
}
}
}
当设置异常时,会捕获异常信息并存储:
public bool TrySetException(Exception error)
{
// ...
this.error = new ExceptionHolder(ExceptionDispatchInfo.Capture(error));
// ...
}
自动重置版本:AutoResetUniTaskCompletionSource
AutoResetUniTaskCompletionSource是可重用的完成源实现,通过对象池优化性能:
public static AutoResetUniTaskCompletionSource Create()
{
if (!pool.TryPop(out var result))
{
result = new AutoResetUniTaskCompletionSource();
}
result.version = result.core.Version;
TaskTracker.TrackActiveTask(result, 2);
return result;
}
使用完成后通过TryReturn方法归还到对象池:
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
return pool.TryPush(this);
}
实际应用示例
基础使用模式
创建UniTaskCompletionSource并设置结果:
var completionSource = new UniTaskCompletionSource();
// 在某个异步操作完成后设置结果
completionSource.TrySetResult();
// 等待结果
await completionSource.Task;
带返回值的使用方式
使用泛型版本UniTaskCompletionSource<T>:
var completionSource = new UniTaskCompletionSource<string>();
// 设置字符串结果
completionSource.TrySetResult("操作完成");
// 获取结果
var result = await completionSource.Task;
Debug.Log(result); // 输出"操作完成"
取消操作处理
var cts = new CancellationTokenSource();
var completionSource = new UniTaskCompletionSource();
// 设置取消状态
completionSource.TrySetCanceled(cts.Token);
try
{
await completionSource.Task;
}
catch (OperationCanceledException ex)
{
Debug.Log("操作已取消: " + ex.Message);
}
线程安全与性能优化
并发控制机制
UniTaskCompletionSource通过双重检查锁定(double-checked locking)确保线程安全:
public void OnCompleted(Action<object> continuation, object state, short token)
{
if (gate == null)
{
Interlocked.CompareExchange(ref gate, new object(), null);
}
var lockGate = Thread.VolatileRead(ref gate);
lock (lockGate) // 等待TrySignalCompletion完成状态转换
{
// ...
}
}
性能优化策略
- 对象池化:
AutoResetUniTaskCompletionSource通过对象池减少GC压力 - 状态压缩:使用
int存储状态枚举,减少内存占用 - 延迟分配:仅在需要时创建
secondaryContinuationList等集合对象 - 避免装箱:通过泛型实现避免值类型装箱操作
总结与最佳实践
UniTaskCompletionSource作为UniTask库的核心组件,提供了高效、灵活的异步结果控制机制。在使用时应注意:
- 优先使用池化版本:对于频繁创建和释放的场景,优先选择
AutoResetUniTaskCompletionSource以减少GC - 正确处理异常:确保所有异常都被妥善捕获和处理,避免未观察到的异常导致程序崩溃
- 避免重复设置结果:
TrySetXxx方法返回bool值,应检查返回结果确保状态设置成功 - 注意线程安全:在多线程环境下使用时,确保正确处理并发问题
通过合理使用UniTaskCompletionSource,开发者可以构建出高效、可靠的异步操作流程,充分发挥UniTask在Unity环境中的性能优势。
参考资料
- UniTask官方文档:docs/index.md
- UniTask单元测试:src/UniTask.NetCoreTests/CompletionSourceTest.cs
- UniTask源码:src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskCompletionSource.cs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



