想研究这个东西,一开始是在使用YooAsset这个资源管理框架时发现的这个功能实现,挺有意思的,把很多任务通过异步的方式进行实现。

自己写之前,肯定要搞懂原理,所以直接询问了AI,这里借助deepwiki.com这个网站询问。询问道的答案是:https://deepwiki.com/search/operationsystem_bd3038e4-1762-402c-a354-72c5b28c5f7b

梳理逻辑

平时使用unitask创建异步任务时,一般放在函数里执行,而如果我们要对一个复杂的内容做一个操作等待,总不能把代码全部仍在一个函数里,这样会导致整个系统复杂度过高,影响开发效率。

通过AI询问阅读YooAsset源码得知,其使用的是一个集中式的操作管理器和分层的异步操作架构,基于unity协程实现,在异步基类上继承了 IEnumerator, IComparable<AsyncOperationBase> 接口,同时内部有一个C#的Task实现(unitask支持从这两个异步中直接使用),并且内部有一个状态枚举,用来确定异步操作状态。

整体原理就是首先异步管理器,有一个一步系统的StartOperation 函数,把制作好的异步操作,传递进入,会自动的把这个异步操作压入队列中(后续在Update函数下处理),并且如果异步状态为初始状态(None),则会自动调用异步操作的StartOperation函数,以标记其启动,便于在其他生命周期函数内的操作可正常进行。管理器会在每帧调用异步操作内的帧更新函数,通过其具体的实现,决定异步状态;完成时标记IsDone=true ,告知异步完成,以便于触发TaskCompletionSource 完成信号,告知上层等待异步完成操作的上下文,结束等待,继续下一步操作。

总结就是,异步任务创建好后,加入到一个自动调用执行管理器,让其自动调用update更新状态,业务层仅需等待异步完成即可。

开发

这里不打算兼用unity的协程和C#Task,直接使用unitask实现。AI给的方案有两种,一种是UniTaskCompletionSource ,也是最简单的,还有一种就是实现IUniTaskSource 接口。

IUniTaskSource 实现这里就不展开讨论了,后续可能会考虑研究其实现。因为翻看UniTaskCompletionSource 的实现,是可以看到其内部就是基于IUniTaskSource 的实现,没必要对其进行二次实现。也就是只需要在异步类中添加如下代码,注意在异步操作类中,要在取消和成功失败侧也要操作UniTaskCompletionSource 变量,便于传递状态。

 
        /// <summary>
        /// 异步操作任务
        /// 简易的异步实现,可不使用回调直接进行异步等待
        /// </summary>
        public UniTask UniTask(CancellationToken cancellationToken = default)
        {
            if (_utcs == null)
            {
                _utcs = new UniTaskCompletionSource();
                if (IsDone)
                    _utcs.TrySetResult();
            }
            this.cancellationToken = cancellationToken;
            // 注册取消回调
            cancellationToken.Register(AbortOperation);
            return _utcs.Task;
        }  
        /// <summary>
        /// 外部请求取消令牌
        /// </summary>
        CancellationToken cancellationToken;
        private UniTaskCompletionSource _utcs;