文章

05 - ETTask WaitAny和WaitAll

05 - ETTask WaitAny和WaitAll

ETTaskHelper 是 ET 框架中用于处理多个 ETTask 协同工作的工具类,提供了 WaitAnyWaitAll 方法,用于等待多个任务中的任意一个完成或全部完成。它的核心实现依赖于一个内部的 CoroutineBlocker 类。下面我们将详细解读 ETTaskHelper 的源码及其工作原理。


1. 核心功能

ETTaskHelper 提供了以下方法:

  1. WaitAny:等待多个任务中的任意一个完成。
  2. WaitAll:等待多个任务全部完成。
  3. IsCancel:检查 ETCancellationToken 是否已取消。

这些方法通过内部的 CoroutineBlocker 类实现任务的协同等待。


2. CoroutineBlocker 的实现

CoroutineBlockerETTaskHelper 的核心类,用于管理多个任务的完成状态。以下是它的关键逻辑:

(1) 成员变量

1
2
private int count; // 需要等待的任务数量
private ETTask tcs; // 用于通知所有任务完成的 ETTask
  • count:记录尚未完成的任务数量。
  • tcs:一个 ETTask 实例,用于在所有任务完成后触发完成通知。

(2) 构造函数

1
2
3
4
public CoroutineBlocker(int count)
{
    this.count = count;
}
  • 初始化时需要传入需要等待的任务数量。

(3) RunSubCoroutineAsync 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public async ETTask RunSubCoroutineAsync(ETTask task)
{
    try
    {
        await task; // 等待任务完成
    }
    finally
    {
        --this.count; // 任务完成,减少计数
        
        if (this.count <= 0 && this.tcs != null)
        {
            ETTask t = this.tcs;
            this.tcs = null;
            t.SetResult(); // 所有任务完成,触发完成通知
        }
    }
}
  • 等待传入的任务完成。注意这里传入的任务是需要监听的任务,如果该任务await通过,则总计数-1
  • 无论任务成功还是失败,都会减少 count 计数。
  • 如果所有任务都完成(count <= 0),并且 tcs 不为空(注意,这里的tcs是CoroutineBlocker中创建的ETTask,用来等待所有需要监听的任务被执行完之后才标记完成),则调用 tcs.SetResult() 通知等待方。

(4) WaitAsync 方法

1
2
3
4
5
6
7
8
9
public async ETTask WaitAsync()
{
    if (this.count <= 0)
    {
        return; // 如果所有任务已经完成,直接返回
    }
    this.tcs = ETTask.Create(true); // 创建一个 ETTask,用于通知完成
    await tcs; // 等待所有任务完成
}
  • 如果所有任务已经完成(count <= 0),直接返回。
  • 否则,创建一个 ETTask 并等待其完成。

3. WaitAnyWaitAll 的实现

WaitAnyWaitAll 方法都依赖于 CoroutineBlocker 来实现任务的协同等待。

(1) WaitAny

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static async ETTask WaitAny(List<ETTask> tasks)
{
    if (tasks.Count == 0)
    {
        return; // 如果任务列表为空,直接返回
    }

    CoroutineBlocker coroutineBlocker = new CoroutineBlocker(1); // 只需要等待任意一个任务完成

    foreach (ETTask task in tasks)
    {
        coroutineBlocker.RunSubCoroutineAsync(task).Coroutine(); // 启动所有任务
    }

    await coroutineBlocker.WaitAsync(); // 等待任意一个任务完成
}
  • 创建一个 CoroutineBlocker,设置 count 为 1,表示只需要等待任意一个任务完成。
  • 遍历任务列表,启动所有任务。
  • 调用 WaitAsync 等待任意一个任务完成。

(2) WaitAll

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static async ETTask WaitAll(List<ETTask> tasks)
{
    if (tasks.Count == 0)
    {
        return; // 如果任务列表为空,直接返回
    }

    CoroutineBlocker coroutineBlocker = new CoroutineBlocker(tasks.Count); // 需要等待所有任务完成

    foreach (ETTask task in tasks)
    {
        coroutineBlocker.RunSubCoroutineAsync(task).Coroutine(); // 启动所有任务
    }

    await coroutineBlocker.WaitAsync(); // 等待所有任务完成
}
  • 创建一个 CoroutineBlocker,设置 count 为任务数量,表示需要等待所有任务完成。
  • 遍历任务列表,启动所有任务。
  • 调用 WaitAsync 等待所有任务完成。

4. IsCancel 方法

1
2
3
4
5
6
7
8
public static bool IsCancel(this ETCancellationToken self)
{
    if (self == null)
    {
        return false; // 如果取消令牌为空,返回 false
    }
    return self.IsDispose(); // 检查取消令牌是否已释放
}
  • 用于检查 ETCancellationToken 是否已取消。
  • 如果取消令牌为空,返回 false
  • 否则,调用 IsDispose 方法检查取消状态。

5. 使用示例

以下是 ETTaskHelper 的使用示例:

(1) 等待任意一个任务完成

1
2
3
4
5
ETTask task1 = DoSomethingAsync();
ETTask task2 = DoSomethingElseAsync();

await ETTaskHelper.WaitAny(new List<ETTask> { task1, task2 });
Console.WriteLine("任意一个任务已完成");

(2) 等待所有任务完成

1
2
3
4
5
ETTask task1 = DoSomethingAsync();
ETTask task2 = DoSomethingElseAsync();

await ETTaskHelper.WaitAll(new List<ETTask> { task1, task2 });
Console.WriteLine("所有任务已完成");

(3) 检查取消令牌

1
2
3
4
5
6
ETCancellationToken cancellationToken = new ETCancellationToken();

if (cancellationToken.IsCancel())
{
    Console.WriteLine("任务已取消");
}

6. 总结

ETTaskHelper 是 ET 框架中用于处理多个 ETTask 协同工作的工具类,提供了 WaitAnyWaitAll 方法,用于等待多个任务中的任意一个完成或全部完成。其核心实现依赖于内部的 CoroutineBlocker 类,通过计数器和 ETTask 的协同机制实现任务的协同等待。

  • WaitAny:等待任意一个任务完成。
  • WaitAll:等待所有任务完成。
  • IsCancel:检查取消令牌的状态。

通过 ETTaskHelper,开发者可以更方便地处理多个异步任务的协同逻辑,提升代码的可读性和可维护性。

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

© admin. 保留部分权利。

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