refactor(coroutine): 重构协程等待机制并移除Held状态

- 移除了CoroutineState中的Held状态
- WaitForAllCoroutines不再依赖CoroutineScheduler参数
- 使用HashSet替代IReadOnlyList存储待处理协程句柄
- 添加NotifyCoroutineComplete方法通知协程完成
- 修改HandleYieldInstruction方法使用switch表达式处理不同等待指令
- 移除WaitForCoroutine逻辑中对Held状态的设置
- 添加对WaitForAllCoroutines的完成通知支持
This commit is contained in:
GeWuYou 2026-02-01 15:27:49 +08:00
parent b4360b01ca
commit ae37b8c5f1
5 changed files with 76 additions and 43 deletions

View File

@ -15,11 +15,6 @@ public enum CoroutineState
/// </summary>
Paused,
/// <summary>
/// 协程被锁定或等待其他协程完成
/// </summary>
Held,
/// <summary>
/// 协程已完成执行
/// </summary>

View File

@ -27,6 +27,5 @@ internal class CoroutineMetadata
/// </summary>
public bool IsActive =>
State is CoroutineState.Running
or CoroutineState.Paused
or CoroutineState.Held;
or CoroutineState.Paused;
}

View File

@ -161,17 +161,40 @@ public sealed class CoroutineScheduler(
/// <param name="slot">协程槽位</param>
/// <param name="instruction">yield指令</param>
private void HandleYieldInstruction(CoroutineSlot slot, IYieldInstruction instruction)
{
switch (instruction)
{
// 处理 WaitForCoroutine 指令
if (instruction is WaitForCoroutine waitForCoroutine)
case WaitForCoroutine waitForCoroutine:
{
// 启动被等待的协程并建立等待关系
var targetHandle = Run(waitForCoroutine.Coroutine);
slot.Waiting = waitForCoroutine;
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;
}
}
@ -250,16 +273,6 @@ public sealed class CoroutineScheduler(
if (!_metadata.ContainsKey(target))
return;
if (_metadata.TryGetValue(current, out var meta))
{
var slot = _slots[meta.SlotIndex];
if (slot != null)
{
slot.State = CoroutineState.Held;
meta.State = CoroutineState.Held;
}
}
if (!_waiting.TryGetValue(target, out var set))
{
set = [];
@ -354,10 +367,15 @@ public sealed class CoroutineScheduler(
if (!_metadata.TryGetValue(waiter, out var meta)) continue;
var s = _slots[meta.SlotIndex];
if (s == null) continue;
// 通知 WaitForCoroutine 指令协程已完成
if (s.Waiting is WaitForCoroutine wfc)
switch (s.Waiting)
{
// 通知 WaitForCoroutine 指令协程已完成
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(scheduler, handles);
yield return new WaitForAllCoroutines(handles);
}
/// <summary>

View File

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