05 - ETTask WaitAny和WaitAll
05 - ETTask WaitAny和WaitAll
ETTaskHelper
是 ET 框架中用于处理多个 ETTask
协同工作的工具类,提供了 WaitAny
和 WaitAll
方法,用于等待多个任务中的任意一个完成或全部完成。它的核心实现依赖于一个内部的 CoroutineBlocker
类。下面我们将详细解读 ETTaskHelper
的源码及其工作原理。
1. 核心功能
ETTaskHelper
提供了以下方法:
WaitAny
:等待多个任务中的任意一个完成。WaitAll
:等待多个任务全部完成。IsCancel
:检查ETCancellationToken
是否已取消。
这些方法通过内部的 CoroutineBlocker
类实现任务的协同等待。
2. CoroutineBlocker
的实现
CoroutineBlocker
是 ETTaskHelper
的核心类,用于管理多个任务的完成状态。以下是它的关键逻辑:
(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. WaitAny
和 WaitAll
的实现
WaitAny
和 WaitAll
方法都依赖于 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
协同工作的工具类,提供了 WaitAny
和 WaitAll
方法,用于等待多个任务中的任意一个完成或全部完成。其核心实现依赖于内部的 CoroutineBlocker
类,通过计数器和 ETTask
的协同机制实现任务的协同等待。
WaitAny
:等待任意一个任务完成。WaitAll
:等待所有任务完成。IsCancel
:检查取消令牌的状态。
通过 ETTaskHelper
,开发者可以更方便地处理多个异步任务的协同逻辑,提升代码的可读性和可维护性。
本文由作者按照 CC BY 4.0 进行授权