05 - ETTask
05 - ETTask
ETTask相比于Task的优点:
1
2
3
4
5
生成代码极简,去除了多线程的支持,性能最好
对象池消除了Task GC
去掉了ETVoid
借助DeepSeek的辅助,从 设计目标、核心组件、工作原理 和 使用场景 四个方面,详细解读 ETTask
的实现。
1. 设计目标
ETTask
是 ET 框架中的异步任务实现,主要设计目标是:
- 轻量高效:适用于游戏开发中的高性能需求,避免线程阻塞和上下文切换。
- 协程支持:通过
async/await
实现协程逻辑,简化异步编程。 - 对象池优化:通过对象池减少内存分配,提升性能。
- 异常处理:提供统一的异常处理机制,避免异步任务中的异常丢失。
2. 核心组件
ETTask
的实现涉及多个核心组件,以下是它们的职责和关系:
(1) ETTask
和 ETTask<T>
- 作用:表示一个异步任务,类似于 C# 的
Task
和Task<T>
。 - 关键特性:
- 实现了
ICriticalNotifyCompletion
接口,支持await
语法。 - 通过
SetResult
和SetException
标记任务完成状态。 - 支持对象池,减少内存分配。
- 实现了
(2) ETAsyncTaskMethodBuilder
和 ETAsyncTaskMethodBuilder<T>
- 作用:编译器生成的异步状态机的构建器,负责管理异步任务的生命周期。
- 关键方法:
Create
:创建异步任务。Start
:启动状态机。AwaitOnCompleted
和AwaitUnsafeOnCompleted
:注册回调,挂起状态机。SetResult
和SetException
:标记任务完成状态。
(3) ETVoid
和 ETTaskCompleted
- 作用:表示无返回值的异步任务,用于简化协程逻辑。
- 关键特性:
ETVoid
是一个空结构体,用于表示无返回值的协程。ETTaskCompleted
是一个已完成的任务,用于快速返回。
(4) ETTaskHelper
- 作用:提供常用的异步任务工具方法,例如
WaitAll
和WaitAny
。 - 关键特性:
- 通过
CoroutineBlocker
实现多个任务的协同等待。
- 通过
(5) ETCancellationToken
- 作用:用于取消异步任务。
- 关键特性:
- 通过
Cancel
方法触发取消操作,调用注册的回调。
- 通过
3. 工作原理
ETTask
的核心工作原理是基于 异步状态机 和 回调机制,以下是其工作流程:
(1) 异步任务的创建
- 通过
ETTask.Create
或ETTask<T>.Create
创建一个异步任务。 - 如果启用了对象池,任务实例会从对象池中获取,避免频繁的内存分配。
(2) 异步任务的启动
- 编译器生成的代码会调用
ETAsyncTaskMethodBuilder.Start
,启动异步状态机。 - 状态机的
MoveNext
方法开始执行异步逻辑。
(3) 异步任务的挂起
- 当遇到
await
时,编译器生成的代码会调用AwaitOnCompleted
或AwaitUnsafeOnCompleted
。 - 这些方法将状态机的
MoveNext
方法注册为回调,保存到ETTask
的callback
字段中。 - 状态机挂起,控制权交还给调用方。
(4) 异步任务的恢复
- 当异步操作完成时,调用
SetResult
或SetException
标记任务完成状态。 SetResult
或SetException
会触发之前注册的回调(即MoveNext
方法)。- 状态机从挂起点继续执行。
(5) 异步任务的完成
- 当状态机执行完毕时,调用
SetResult
或SetException
标记任务完成。 - 如果启用了对象池,任务实例会被回收到对象池中。
4. 使用场景
ETTask
适用于以下场景:
(1) 协程逻辑
- 通过
async/await
实现协程逻辑,简化异步编程。 - 例如:
1 2 3 4 5
public async ETTask MyCoroutine() { await TimerComponent.Instance.WaitAsync(1000); // 等待 1 秒 Console.WriteLine("1 秒后执行"); }
(2) 多任务协同
- 使用
ETTaskHelper.WaitAll
或ETTaskHelper.WaitAny
实现多个任务的协同等待。 - 例如:
1 2 3 4 5 6
public async ETTask MyTask() { ETTask task1 = DoSomethingAsync(); ETTask task2 = DoSomethingElseAsync(); await ETTaskHelper.WaitAll(task1, task2); // 等待所有任务完成 }
(3) 取消操作
- 使用
ETCancellationToken
实现异步任务的取消。 - 例如:
1 2 3 4
public async ETTask MyTask(ETCancellationToken cancellationToken) { await TimerComponent.Instance.WaitAsync(1000, cancellationToken); // 等待 1 秒,支持取消 }
5. 关键代码解析
(1) ETTask
的回调注册
1
2
3
4
5
6
7
8
9
10
public void UnsafeOnCompleted(Action action)
{
if (this.state != AwaiterStatus.Pending)
{
action?.Invoke();
return;
}
this.callback = action;
}
- 如果任务已完成,直接调用回调。
- 如果任务未完成,将回调保存到
callback
字段中,等待任务完成时触发。
(2) ETTask
的任务完成
1
2
3
4
5
6
7
8
9
10
11
12
13
public void SetResult()
{
if (this.state != AwaiterStatus.Pending)
{
throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
}
this.state = AwaiterStatus.Succeeded;
Action c = this.callback as Action;
this.callback = null;
c?.Invoke();
}
- 检查任务状态,避免多次完成。
- 标记任务状态为
Succeeded
。 - 触发之前注册的回调(即
MoveNext
方法)。
(3) ETAsyncTaskMethodBuilder
的启动
1
2
3
4
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
stateMachine.MoveNext();
}
- 启动状态机,调用
MoveNext
方法开始执行异步逻辑。
6. 总结
ETTask
是 ET 框架中的异步任务实现,通过 异步状态机 和 回调机制 实现高效的协程逻辑。其核心设计包括:
- 轻量高效:通过对象池和状态机优化性能。
- 协程支持:通过
async/await
简化异步编程。 - 异常处理:提供统一的异常处理机制。
通过分析 ETTask
的源码,我们可以更好地理解其工作原理,并在实际开发中灵活运用。希望这个解读对你有所帮助!
本文由作者按照 CC BY 4.0 进行授权