文章

05 - ETTask

05 - ETTask

ETTask相比于Task的优点:

1
2
3
4
5
生成代码极简,去除了多线程的支持,性能最好

对象池消除了Task GC

去掉了ETVoid

借助DeepSeek的辅助,从 设计目标核心组件工作原理使用场景 四个方面,详细解读 ETTask 的实现。


1. 设计目标

ETTask 是 ET 框架中的异步任务实现,主要设计目标是:

  1. 轻量高效:适用于游戏开发中的高性能需求,避免线程阻塞和上下文切换。
  2. 协程支持:通过 async/await 实现协程逻辑,简化异步编程。
  3. 对象池优化:通过对象池减少内存分配,提升性能。
  4. 异常处理:提供统一的异常处理机制,避免异步任务中的异常丢失。

2. 核心组件

ETTask 的实现涉及多个核心组件,以下是它们的职责和关系:

(1) ETTaskETTask<T>

  • 作用:表示一个异步任务,类似于 C# 的 TaskTask<T>
  • 关键特性
    • 实现了 ICriticalNotifyCompletion 接口,支持 await 语法。
    • 通过 SetResultSetException 标记任务完成状态。
    • 支持对象池,减少内存分配。

(2) ETAsyncTaskMethodBuilderETAsyncTaskMethodBuilder<T>

  • 作用:编译器生成的异步状态机的构建器,负责管理异步任务的生命周期。
  • 关键方法
    • Create:创建异步任务。
    • Start:启动状态机。
    • AwaitOnCompletedAwaitUnsafeOnCompleted:注册回调,挂起状态机。
    • SetResultSetException:标记任务完成状态。

(3) ETVoidETTaskCompleted

  • 作用:表示无返回值的异步任务,用于简化协程逻辑。
  • 关键特性
    • ETVoid 是一个空结构体,用于表示无返回值的协程。
    • ETTaskCompleted 是一个已完成的任务,用于快速返回。

(4) ETTaskHelper

  • 作用:提供常用的异步任务工具方法,例如 WaitAllWaitAny
  • 关键特性
    • 通过 CoroutineBlocker 实现多个任务的协同等待。

(5) ETCancellationToken

  • 作用:用于取消异步任务。
  • 关键特性
    • 通过 Cancel 方法触发取消操作,调用注册的回调。

3. 工作原理

ETTask 的核心工作原理是基于 异步状态机回调机制,以下是其工作流程:

(1) 异步任务的创建

  • 通过 ETTask.CreateETTask<T>.Create 创建一个异步任务。
  • 如果启用了对象池,任务实例会从对象池中获取,避免频繁的内存分配。

(2) 异步任务的启动

  • 编译器生成的代码会调用 ETAsyncTaskMethodBuilder.Start,启动异步状态机。
  • 状态机的 MoveNext 方法开始执行异步逻辑。

(3) 异步任务的挂起

  • 当遇到 await 时,编译器生成的代码会调用 AwaitOnCompletedAwaitUnsafeOnCompleted
  • 这些方法将状态机的 MoveNext 方法注册为回调,保存到 ETTaskcallback 字段中。
  • 状态机挂起,控制权交还给调用方。

(4) 异步任务的恢复

  • 当异步操作完成时,调用 SetResultSetException 标记任务完成状态。
  • SetResultSetException 会触发之前注册的回调(即 MoveNext 方法)。
  • 状态机从挂起点继续执行。

(5) 异步任务的完成

  • 当状态机执行完毕时,调用 SetResultSetException 标记任务完成。
  • 如果启用了对象池,任务实例会被回收到对象池中。

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.WaitAllETTaskHelper.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 框架中的异步任务实现,通过 异步状态机回调机制 实现高效的协程逻辑。其核心设计包括:

  1. 轻量高效:通过对象池和状态机优化性能。
  2. 协程支持:通过 async/await 简化异步编程。
  3. 异常处理:提供统一的异常处理机制。

通过分析 ETTask 的源码,我们可以更好地理解其工作原理,并在实际开发中灵活运用。希望这个解读对你有所帮助!

本文由作者按照 CC BY 4.0 进行授权

© admin. 保留部分权利。

本站由 Jekyll 生成,采用 Chirpy 主题。