19 KiB
19 KiB
OperationSystem 异步操作系统
模块概述
OperationSystem 是 YooAsset 资源管理系统的异步操作调度核心,负责管理所有异步操作的生命周期、调度执行和状态追踪。该模块提供了统一的异步操作抽象,支持协程、async/await、回调等多种异步编程模式。
核心职责
- 异步操作的统一抽象和生命周期管理
- 基于优先级的操作调度
- 时间切片执行(防止主线程阻塞)
- 多种异步编程模式支持
- 操作状态追踪和调试信息收集
设计目标
| 目标 | 说明 |
|---|---|
| 统一抽象 | 所有异步操作继承同一基类,接口一致 |
| 灵活调度 | 支持优先级排序、时间切片、帧预算控制 |
| 多模式支持 | 协程(IEnumerator)、Task(async/await)、回调 |
| 可调试性 | 完整的状态追踪、耗时统计、层级关系 |
| 线程安全 | 所有调度逻辑在主线程执行 |
架构概念
系统架构
┌─────────────────────────────────────────────────────────┐
│ 上层调用者 │
│ (ResourceManager / FileSystem / 业务层) │
└─────────────────────────┬───────────────────────────────┘
│ StartOperation()
┌─────────────────────────▼───────────────────────────────┐
│ OperationSystem │
│ (调度器) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 优先级队列 │ │ 时间切片 │ │ 回调通知 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────┬───────────────────────────────┘
│ UpdateOperation()
┌─────────────────────────▼───────────────────────────────┐
│ AsyncOperationBase │
│ (操作基类) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 状态机 │ │ 子任务管理 │ │ 异步模式 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
核心组件
- OperationSystem: 静态调度器,管理所有操作的执行
- AsyncOperationBase: 异步操作基类,定义生命周期和状态
- GameAsyncOperation: 游戏层操作基类,提供更友好的 API
- EOperationStatus: 操作状态枚举
文件结构
OperationSystem/
├── EOperationStatus.cs # 操作状态枚举
├── AsyncOperationBase.cs # 异步操作基类
├── OperationSystem.cs # 异步操作调度器
└── GameAsyncOperation.cs # 游戏层操作基类
枚举定义
EOperationStatus(操作状态)
public enum EOperationStatus
{
None, // 未开始
Processing, // 处理中
Succeed, // 已成功
Failed // 已失败
}
状态转换:
StartOperation() InternalUpdate()
None ─────────────────► Processing ─────────────────┬──► Succeed
│
└──► Failed
核心类说明
AsyncOperationBase(异步操作基类)
所有异步操作的抽象基类,实现了 IEnumerator 和 IComparable<AsyncOperationBase> 接口。
公共属性
| 属性 | 类型 | 说明 |
|---|---|---|
Priority |
uint |
任务优先级(值越大越优先) |
Status |
EOperationStatus |
当前状态 |
Error |
string |
错误信息(失败时) |
Progress |
float |
处理进度(0-1) |
PackageName |
string |
所属包裹名称 |
IsDone |
bool |
是否已完成(Succeed 或 Failed) |
Task |
Task |
用于 async/await |
BeginTime |
string |
开始时间(调试用) |
ProcessTime |
long |
处理耗时毫秒(调试用) |
公共事件
/// <summary>
/// 完成事件(支持后注册立即触发)
/// </summary>
public event Action<AsyncOperationBase> Completed;
公共方法
/// <summary>
/// 同步等待异步操作完成
/// </summary>
public void WaitForAsyncComplete();
内部抽象方法(子类实现)
| 方法 | 说明 |
|---|---|
InternalStart() |
操作开始时调用 |
InternalUpdate() |
每帧更新时调用 |
InternalAbort() |
操作中止时调用(可选) |
InternalWaitForAsyncComplete() |
同步等待时调用(可选) |
InternalGetDesc() |
获取操作描述(可选) |
子任务管理
// 子任务列表
internal readonly List<AsyncOperationBase> Childs;
// 添加/移除子任务
internal void AddChildOperation(AsyncOperationBase child);
internal void RemoveChildOperation(AsyncOperationBase child);
OperationSystem(调度器)
静态类,负责异步操作的调度和管理。
配置属性
/// <summary>
/// 每帧最大执行时间(毫秒)
/// 默认值:long.MaxValue(无限制)
/// </summary>
public static long MaxTimeSlice { set; get; }
/// <summary>
/// 当前帧是否已超时
/// </summary>
public static bool IsBusy { get; }
核心方法
/// <summary>
/// 初始化异步操作系统
/// </summary>
public static void Initialize();
/// <summary>
/// 每帧更新(由 YooAssets 驱动)
/// </summary>
public static void Update();
/// <summary>
/// 销毁所有操作
/// </summary>
public static void DestroyAll();
/// <summary>
/// 清理指定包裹的所有操作
/// </summary>
public static void ClearPackageOperation(string packageName);
/// <summary>
/// 启动异步操作
/// </summary>
public static void StartOperation(string packageName, AsyncOperationBase operation);
回调监听
/// <summary>
/// 注册任务开始回调
/// </summary>
public static void RegisterStartCallback(Action<string, AsyncOperationBase> callback);
/// <summary>
/// 注册任务结束回调
/// </summary>
public static void RegisterFinishCallback(Action<string, AsyncOperationBase> callback);
GameAsyncOperation(游戏层基类)
继承 AsyncOperationBase,为业务层提供更友好的 API。
public abstract class GameAsyncOperation : AsyncOperationBase
{
/// <summary>
/// 异步操作开始
/// </summary>
protected abstract void OnStart();
/// <summary>
/// 异步操作更新
/// </summary>
protected abstract void OnUpdate();
/// <summary>
/// 异步操作终止
/// </summary>
protected abstract void OnAbort();
/// <summary>
/// 异步等待完成(可选重写)
/// </summary>
protected virtual void OnWaitForAsyncComplete();
/// <summary>
/// 异步操作系统是否繁忙
/// </summary>
protected bool IsBusy();
/// <summary>
/// 终止异步操作
/// </summary>
protected void Abort();
}
异步编程模式
1. 协程模式(IEnumerator)
IEnumerator LoadAsset()
{
var operation = package.LoadAssetAsync<GameObject>("Assets/Prefab.prefab");
yield return operation;
if (operation.Status == EOperationStatus.Succeed)
{
GameObject prefab = operation.AssetObject as GameObject;
}
}
2. Task 模式(async/await)
async Task LoadAssetAsync()
{
var operation = package.LoadAssetAsync<GameObject>("Assets/Prefab.prefab");
await operation.Task;
if (operation.Status == EOperationStatus.Succeed)
{
GameObject prefab = operation.AssetObject as GameObject;
}
}
3. 回调模式(Completed 事件)
void LoadAsset()
{
var operation = package.LoadAssetAsync<GameObject>("Assets/Prefab.prefab");
operation.Completed += OnLoadCompleted;
}
void OnLoadCompleted(AsyncOperationBase op)
{
var operation = op as AssetHandle;
if (operation.Status == EOperationStatus.Succeed)
{
GameObject prefab = operation.AssetObject as GameObject;
}
}
4. 同步等待模式
void LoadAssetSync()
{
var operation = package.LoadAssetAsync<GameObject>("Assets/Prefab.prefab");
operation.WaitForAsyncComplete(); // 阻塞等待完成
if (operation.Status == EOperationStatus.Succeed)
{
GameObject prefab = operation.AssetObject as GameObject;
}
}
调度机制
优先级调度
操作按 Priority 属性降序排列,优先级高的操作先执行。
var operation = package.LoadAssetAsync<GameObject>(location);
operation.Priority = 100; // 设置高优先级
排序规则:
- 新操作添加时检查是否需要排序
- 仅当存在非零优先级时触发排序
- 使用
List.Sort()进行原地排序
时间切片
通过 MaxTimeSlice 控制每帧最大执行时间,防止主线程阻塞。
// 设置每帧最多执行 8 毫秒
OperationSystem.MaxTimeSlice = 8;
执行流程:
每帧 Update()
│
├── 记录帧开始时间 _frameTime
│
└── 遍历操作队列
│
├── 检查 IsBusy(是否超时)
│ │
│ └── 超时则中断本帧
│
└── 执行 operation.UpdateOperation()
操作生命周期
┌─────────────────────────────────────────────────────────────────┐
│ 操作生命周期 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 创建操作 │
│ └── Status = None │
│ │
│ 2. StartOperation() │
│ ├── Status = Processing │
│ ├── DebugBeginRecording() │
│ ├── InternalStart() │
│ └── 添加到 _newList │
│ │
│ 3. Update() - 每帧调度 │
│ ├── 移除已完成操作 │
│ ├── 合并 _newList 到 _operations │
│ ├── 按优先级排序(如需要) │
│ └── 遍历执行 UpdateOperation() │
│ │
│ 4. UpdateOperation() │
│ ├── DebugUpdateRecording() │
│ ├── InternalUpdate() │
│ └── 检查 IsDone │
│ │ │
│ └── 完成时: │
│ ├── IsFinish = true │
│ ├── Progress = 1f │
│ ├── DebugEndRecording() │
│ ├── 触发 Completed 回调 │
│ └── 设置 TaskCompletionSource │
│ │
│ 5. 下一帧移除完成的操作 │
│ │
└─────────────────────────────────────────────────────────────────┘
调试支持
调试信息结构
internal struct DebugOperationInfo
{
public string OperationName; // 操作类型名
public string OperationDesc; // 操作描述
public uint Priority; // 优先级
public float Progress; // 进度
public string BeginTime; // 开始时间
public long ProcessTime; // 处理耗时(毫秒)
public string Status; // 状态
public List<DebugOperationInfo> Childs; // 子操作
}
获取调试信息
// 获取指定包裹的所有操作信息
var infos = OperationSystem.GetDebugOperationInfos("DefaultPackage");
foreach (var info in infos)
{
Debug.Log($"{info.OperationName}: {info.Status}, {info.ProcessTime}ms");
}
耗时统计
在 DEBUG 模式下自动统计操作耗时:
// 操作完成后可获取耗时
Debug.Log($"开始时间: {operation.BeginTime}");
Debug.Log($"处理耗时: {operation.ProcessTime}ms");
使用示例
自定义异步操作
public class MyCustomOperation : GameAsyncOperation
{
private int _step = 0;
protected override void OnStart()
{
// 初始化操作
_step = 0;
}
protected override void OnUpdate()
{
// 检查系统是否繁忙(时间切片)
if (IsBusy())
return;
// 执行步骤
switch (_step)
{
case 0:
// 第一步
Progress = 0.3f;
_step = 1;
break;
case 1:
// 第二步
Progress = 0.6f;
_step = 2;
break;
case 2:
// 完成
Status = EOperationStatus.Succeed;
break;
}
}
protected override void OnAbort()
{
// 清理资源
}
}
启动自定义操作
var operation = new MyCustomOperation();
OperationSystem.StartOperation("DefaultPackage", operation);
// 使用回调
operation.Completed += (op) =>
{
if (op.Status == EOperationStatus.Succeed)
Debug.Log("操作成功");
};
// 或使用 await
await operation.Task;
带子任务的操作
public class ParentOperation : GameAsyncOperation
{
private ChildOperation _child;
protected override void OnStart()
{
_child = new ChildOperation();
AddChildOperation(_child); // 添加子任务
OperationSystem.StartOperation(PackageName, _child);
}
protected override void OnUpdate()
{
if (_child.IsDone)
{
if (_child.Status == EOperationStatus.Succeed)
Status = EOperationStatus.Succeed;
else
Status = EOperationStatus.Failed;
}
}
protected override void OnAbort()
{
// 子任务会自动中止
}
}
设计模式
模板方法模式
AsyncOperationBase 定义算法骨架,子类实现具体步骤:
AsyncOperationBase
│
├── StartOperation() ──► InternalStart() [子类实现]
├── UpdateOperation() ──► InternalUpdate() [子类实现]
├── AbortOperation() ──► InternalAbort() [子类实现]
└── WaitForAsyncComplete() ──► InternalWaitForAsyncComplete() [子类实现]
状态机模式
操作状态由 EOperationStatus 管理:
┌──────┐ StartOperation() ┌────────────┐ UpdateOperation() ┌─────────┐
│ None │ ─────────────────► │ Processing │ ──────────────────► │ Succeed │
└──────┘ └────────────┘ └─────────┘
│
│ UpdateOperation() / AbortOperation()
▼
┌──────────┐
│ Failed │
└──────────┘
组合模式
通过 Childs 列表支持父子操作关系:
ParentOperation
├── ChildOperation1
├── ChildOperation2
└── ChildOperation3
└── GrandChildOperation
类继承关系
IEnumerator + IComparable<AsyncOperationBase>
│
▼
AsyncOperationBase (抽象基类)
│
├── GameAsyncOperation (游戏层基类)
│ │
│ └── [业务层自定义操作]
│
└── [YooAsset 内部操作]
│
├── InitializationOperation
├── LoadAssetOperation
├── LoadSceneOperation
├── DownloadOperation
└── ...
注意事项
- 主线程执行:所有操作的调度和更新都在 Unity 主线程执行
- 时间切片:设置合理的
MaxTimeSlice避免卡顿(建议 8-16ms) - 同步等待:
WaitForAsyncComplete()会阻塞主线程,谨慎使用 - 子任务中止:父操作中止时会自动中止所有子操作
- 回调异常:
Completed回调中的异常会被捕获并记录,不会中断系统 - 编辑器重置:编辑器中使用
RuntimeInitializeOnLoadMethod自动重置状态 - 循环保护:
WaitForAsyncComplete()有 1000 帧上限,防止无限循环