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> /// </summary>
Paused, Paused,
/// <summary>
/// 协程被锁定或等待其他协程完成
/// </summary>
Held,
/// <summary> /// <summary>
/// 协程已完成执行 /// 协程已完成执行
/// </summary> /// </summary>

View File

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

View File

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

View File

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