refactor(coroutine): 重构 WaitForAllCoroutines 实现

- 修改 WaitForAllCoroutines 构造函数,添加 CoroutineScheduler 参数
- 移除 WaitForAllCoroutines 内部的待处理句柄集合和完成状态管理
- 修改 WaitForAllCoroutines 的 IsDone 属性实现,改为通过调度器检查协程状态
- 移除 WaitForAllCoroutines 的 NotifyCoroutineComplete 方法
- 更新 CoroutineScheduler 中对 WaitForAllCoroutines 的处理逻辑
- 移除调度器中的协程完成通知相关代码
- 更新所有相关测试用例以适应新的构造函数参数
- 添加对 scheduler 参数的空值验证测试
- [release ci]
This commit is contained in:
GeWuYou 2026-02-01 16:53:26 +08:00
parent 65fdea6c12
commit 7242f58029
4 changed files with 53 additions and 84 deletions

View File

@ -36,7 +36,7 @@ public class WaitForAllCoroutinesTests
scheduler.Run(coroutine2)
};
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
Assert.That(wait.IsDone, Is.False);
}
@ -58,7 +58,7 @@ public class WaitForAllCoroutinesTests
scheduler.Run(coroutine2)
};
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
scheduler.Update();
scheduler.Update();
@ -87,7 +87,7 @@ public class WaitForAllCoroutinesTests
scheduler.Run(coroutine3)
};
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
Assert.That(wait.IsDone, Is.False);
Assert.That(executionCount, Is.EqualTo(0));
@ -108,7 +108,7 @@ public class WaitForAllCoroutinesTests
var scheduler = new CoroutineScheduler(timeSource);
var handles = Array.Empty<CoroutineHandle>();
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
Assert.That(wait.IsDone, Is.True);
}
@ -119,7 +119,21 @@ public class WaitForAllCoroutinesTests
[Test]
public void WaitForAllCoroutines_Should_Throw_ArgumentNullException_When_Handles_Is_Null()
{
Assert.Throws<ArgumentNullException>(() => new WaitForAllCoroutines(null!));
var timeSource = new TestTimeSource();
var scheduler = new CoroutineScheduler(timeSource);
Assert.Throws<ArgumentNullException>(() => new WaitForAllCoroutines(scheduler, null!));
}
/// <summary>
/// 验证WaitForAllCoroutines应该抛出ArgumentNullException当scheduler为null
/// </summary>
[Test]
public void WaitForAllCoroutines_Should_Throw_ArgumentNullException_When_Scheduler_Is_Null()
{
var handles = Array.Empty<CoroutineHandle>();
Assert.Throws<ArgumentNullException>(() => new WaitForAllCoroutines(null!, handles));
}
/// <summary>
@ -134,7 +148,7 @@ public class WaitForAllCoroutinesTests
var handles = new List<CoroutineHandle> { scheduler.Run(coroutine) };
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
scheduler.Update();
@ -162,7 +176,7 @@ public class WaitForAllCoroutinesTests
scheduler.Run(coroutine3)
};
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
scheduler.Update();
@ -188,7 +202,7 @@ public class WaitForAllCoroutinesTests
scheduler.Run(coroutine2)
};
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
Assert.That(wait.IsDone, Is.False);
@ -220,7 +234,7 @@ public class WaitForAllCoroutinesTests
scheduler.Run(coroutine2)
};
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
scheduler.Pause(handles[0]);
@ -248,7 +262,7 @@ public class WaitForAllCoroutinesTests
var coroutine = CreateDelayedCoroutine(() => { }, 1.0);
var handles = new List<CoroutineHandle> { scheduler.Run(coroutine) };
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
wait.Update(0.1);
Assert.That(wait.IsDone, Is.False);
@ -268,7 +282,7 @@ public class WaitForAllCoroutinesTests
var handles = new List<CoroutineHandle> { default };
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
Assert.That(wait.IsDone, Is.True);
}
@ -289,7 +303,7 @@ public class WaitForAllCoroutinesTests
default
};
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
scheduler.Update();
@ -309,7 +323,7 @@ public class WaitForAllCoroutinesTests
var handles = new List<CoroutineHandle>();
for (var i = 0; i < 20; i++) handles.Add(scheduler.Run(CreateDelayedCoroutine(() => executionCount++, 1.0)));
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
Assert.That(wait.IsDone, Is.False);
@ -339,7 +353,7 @@ public class WaitForAllCoroutinesTests
scheduler.Run(coroutine3)
};
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
scheduler.Update();
@ -386,7 +400,7 @@ public class WaitForAllCoroutinesTests
var scheduler = new CoroutineScheduler(timeSource);
var handles = Array.Empty<CoroutineHandle>();
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
Assert.That(wait, Is.InstanceOf<IYieldInstruction>());
}
@ -412,7 +426,7 @@ public class WaitForAllCoroutinesTests
scheduler.Update();
scheduler.Update();
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
Assert.That(wait.IsDone, Is.True);
}
@ -430,7 +444,7 @@ public class WaitForAllCoroutinesTests
var handle = scheduler.Run(coroutine);
var handles = new List<CoroutineHandle> { handle, handle };
var wait = new WaitForAllCoroutines(handles);
var wait = new WaitForAllCoroutines(scheduler, handles);
for (var i = 0; i < 12; i++) scheduler.Update();
@ -445,15 +459,6 @@ public class WaitForAllCoroutinesTests
yield break;
}
/// <summary>
/// 创建带回调的协程
/// </summary>
private IEnumerator<IYieldInstruction> CreateCoroutineWithCallback(int id, Action callback)
{
yield return new WaitOneFrame();
callback();
}
/// <summary>
/// 创建延迟协程
/// </summary>

View File

@ -173,25 +173,6 @@ public sealed class CoroutineScheduler(
WaitForCoroutine(slot.Handle, targetHandle);
break;
}
case WaitForAllCoroutines waitForAll:
{
slot.Waiting = waitForAll;
// 为所有待完成的协程建立等待关系
foreach (var handle in waitForAll.PendingHandles)
{
if (_metadata.ContainsKey(handle))
{
WaitForCoroutine(slot.Handle, handle);
}
else
{
// 协程已完成,立即通知
waitForAll.NotifyCoroutineComplete(handle);
}
}
break;
}
default:
slot.Waiting = instruction;
break;
@ -373,9 +354,6 @@ public sealed class CoroutineScheduler(
case WaitForCoroutine wfc:
wfc.Complete();
break;
case WaitForAllCoroutines wfa:
wfa.NotifyCoroutineComplete(handle);
break;
}
s.State = CoroutineState.Running;

View File

@ -86,7 +86,7 @@ public static class CoroutineExtensions
}
// 等待所有协程完成
yield return new WaitForAllCoroutines(handles);
yield return new WaitForAllCoroutines(scheduler, handles);
}
/// <summary>

View File

@ -5,51 +5,37 @@ namespace GFramework.Core.coroutine.instructions;
/// <summary>
/// 等待所有协程完成的等待指令
/// </summary>
public sealed class WaitForAllCoroutines : IYieldInstruction
/// <param name="scheduler">协程调度器,用于检查协程是否存活</param>
/// <param name="handles">协程句柄列表,用于跟踪需要等待的协程</param>
public sealed class WaitForAllCoroutines(
CoroutineScheduler scheduler,
IReadOnlyList<CoroutineHandle> handles)
: IYieldInstruction
{
private readonly HashSet<CoroutineHandle> _pendingHandles;
private bool _isDone;
private readonly IReadOnlyList<CoroutineHandle> _handles =
handles ?? throw new ArgumentNullException(nameof(handles));
private readonly CoroutineScheduler _scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
/// <summary>
/// 初始化 WaitForAllCoroutines 类的新实例
/// 更新方法,在每一帧调用
/// </summary>
/// <param name="handles">要等待完成的协程句柄列表</param>
public WaitForAllCoroutines(IReadOnlyList<CoroutineHandle> handles)
{
ArgumentNullException.ThrowIfNull(handles);
_pendingHandles = new HashSet<CoroutineHandle>(handles);
_isDone = _pendingHandles.Count == 0;
}
/// <summary>
/// 获取所有待完成的协程句柄
/// </summary>
internal IReadOnlyCollection<CoroutineHandle> PendingHandles => _pendingHandles;
/// <summary>
/// 更新方法 - 由调度器调用
/// </summary>
/// <param name="deltaTime">时间增量</param>
/// <param name="deltaTime">自上一帧以来的时间间隔</param>
public void Update(double deltaTime)
{
// 不需要做任何事,由调度器通知完成
// 不需要做任何事
}
/// <summary>
/// 获取一个值,指示是否所有协程都已完成
/// 获取一个值,指示所有协程是否已完成执行
/// </summary>
public bool IsDone => _isDone;
/// <summary>
/// 通知某个协程已完成
/// </summary>
/// <param name="handle">已完成的协程句柄</param>
internal void NotifyCoroutineComplete(CoroutineHandle handle)
/// <returns>当所有协程都已完成时返回true否则返回false</returns>
public bool IsDone
{
// 从待处理句柄集合中移除已完成的协程句柄
_pendingHandles.Remove(handle);
if (_pendingHandles.Count == 0)
_isDone = true;
get
{
// 检查所有协程句柄是否都不在调度器中存活
return _handles.All(handle => !_scheduler.IsCoroutineAlive(handle));
}
}
}