mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
refactor(coroutine): 重构协程等待机制并移除Held状态
- 移除了CoroutineState中的Held状态 - WaitForAllCoroutines不再依赖CoroutineScheduler参数 - 使用HashSet替代IReadOnlyList存储待处理协程句柄 - 添加NotifyCoroutineComplete方法通知协程完成 - 修改HandleYieldInstruction方法使用switch表达式处理不同等待指令 - 移除WaitForCoroutine逻辑中对Held状态的设置 - 添加对WaitForAllCoroutines的完成通知支持
This commit is contained in:
parent
b4360b01ca
commit
ae37b8c5f1
@ -15,11 +15,6 @@ public enum CoroutineState
|
||||
/// </summary>
|
||||
Paused,
|
||||
|
||||
/// <summary>
|
||||
/// 协程被锁定或等待其他协程完成
|
||||
/// </summary>
|
||||
Held,
|
||||
|
||||
/// <summary>
|
||||
/// 协程已完成执行
|
||||
/// </summary>
|
||||
|
||||
@ -27,6 +27,5 @@ internal class CoroutineMetadata
|
||||
/// </summary>
|
||||
public bool IsActive =>
|
||||
State is CoroutineState.Running
|
||||
or CoroutineState.Paused
|
||||
or CoroutineState.Held;
|
||||
or CoroutineState.Paused;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -86,7 +86,7 @@ public static class CoroutineExtensions
|
||||
}
|
||||
|
||||
// 等待所有协程完成
|
||||
yield return new WaitForAllCoroutines(scheduler, handles);
|
||||
yield return new WaitForAllCoroutines(handles);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user