UniTask源码解析:UniTaskCompletionSource与结果设置

UniTask源码解析:UniTaskCompletionSource与结果设置

【免费下载链接】UniTask Provides an efficient allocation free async/await integration for Unity. 【免费下载链接】UniTask 项目地址: https://gitcode.com/gh_mirrors/un/UniTask

在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;
}

关键实现细节:

  1. 使用Interlocked.Increment确保只有一个线程能成功设置结果
  2. 通过s_sentinel哨兵对象处理延续回调的竞态条件
  3. 完成后立即调用已注册的延续回调

异常处理机制

异常处理通过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完成状态转换
    {
        // ...
    }
}

性能优化策略

  1. 对象池化AutoResetUniTaskCompletionSource通过对象池减少GC压力
  2. 状态压缩:使用int存储状态枚举,减少内存占用
  3. 延迟分配:仅在需要时创建secondaryContinuationList等集合对象
  4. 避免装箱:通过泛型实现避免值类型装箱操作

总结与最佳实践

UniTaskCompletionSource作为UniTask库的核心组件,提供了高效、灵活的异步结果控制机制。在使用时应注意:

  1. 优先使用池化版本:对于频繁创建和释放的场景,优先选择AutoResetUniTaskCompletionSource以减少GC
  2. 正确处理异常:确保所有异常都被妥善捕获和处理,避免未观察到的异常导致程序崩溃
  3. 避免重复设置结果TrySetXxx方法返回bool值,应检查返回结果确保状态设置成功
  4. 注意线程安全:在多线程环境下使用时,确保正确处理并发问题

通过合理使用UniTaskCompletionSource,开发者可以构建出高效、可靠的异步操作流程,充分发挥UniTask在Unity环境中的性能优势。

参考资料

【免费下载链接】UniTask Provides an efficient allocation free async/await integration for Unity. 【免费下载链接】UniTask 项目地址: https://gitcode.com/gh_mirrors/un/UniTask

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值