mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-26 06:16:43 +08:00
feat(coroutine): 优化协程执行机制,修复嵌套协程和yield null处理问题
- 修改CoroutineHandle中的协程执行逻辑,实现每帧只推进一步的机制, 避免单帧内过度执行导致的性能问题 - 修复yield null处理逻辑,正确处理等待一帧后继续执行的情况 - 改进嵌套协程处理,确保子协程完成后正确返回到父协程 - 优化WaitUntil条件检查逻辑,确保状态转换正确性 - 在定时任务扩展中添加yield break确保协程正确结束 - 调整协程调度器的更新顺序,先添加新协程再执行更新
This commit is contained in:
parent
f24ec656e6
commit
3e26c84bb1
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ riderModule.iml
|
|||||||
/_ReSharper.Caches/
|
/_ReSharper.Caches/
|
||||||
GFramework.sln.DotSettings.user
|
GFramework.sln.DotSettings.user
|
||||||
.idea/
|
.idea/
|
||||||
|
opencode.json
|
||||||
@ -111,33 +111,85 @@ public class CoroutineHandle : IYieldInstruction, ICoroutineHandle
|
|||||||
{
|
{
|
||||||
if (IsDone) return false;
|
if (IsDone) return false;
|
||||||
|
|
||||||
// 检查并更新当前等待的指令
|
// 如果有等待指令,先更新等待指令
|
||||||
if (_waitingInstruction != null)
|
if (_waitingInstruction != null)
|
||||||
{
|
{
|
||||||
_waitingInstruction.Update(deltaTime);
|
_waitingInstruction.Update(deltaTime);
|
||||||
if (!_waitingInstruction.IsDone) return true;
|
|
||||||
|
// 如果等待指令还未完成,继续等待
|
||||||
|
if (!_waitingInstruction.IsDone)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待指令已完成,清除它
|
||||||
_waitingInstruction = null;
|
_waitingInstruction = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 循环执行直到需要等待或协程完成
|
// 每帧只推进一步(执行一个 MoveNext)
|
||||||
while (_stack.Count > 0 && !IsDone)
|
if (_stack.Count > 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var current = _stack.Peek();
|
var current = _stack.Peek();
|
||||||
if (current.MoveNext())
|
bool hasNext = current.MoveNext();
|
||||||
|
|
||||||
|
if (!hasNext)
|
||||||
{
|
{
|
||||||
|
// 当前枚举器已完成,弹出栈
|
||||||
|
_stack.Pop();
|
||||||
|
|
||||||
|
// 如果栈为空,协程完成
|
||||||
|
if (_stack.Count == 0)
|
||||||
|
{
|
||||||
|
Complete();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则继续执行下一个枚举器(在下一帧)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveNext() 返回 true,有下一个值
|
||||||
var yielded = current.Current;
|
var yielded = current.Current;
|
||||||
var needsWait = ProcessYieldValue(yielded);
|
var needsWait = ProcessYieldValue(yielded);
|
||||||
|
|
||||||
// 如果需要等待,则暂停执行
|
// 如果需要等待,则暂停执行
|
||||||
if (needsWait) return true;
|
if (needsWait)
|
||||||
|
{
|
||||||
// 否则继续执行下一个步骤
|
return true;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果不需要等待(yield null 或嵌套协程),继续处理
|
||||||
|
// 处理 yield null 的情况:yield null 后需要再调用一次 MoveNext 才能知道是否完成
|
||||||
|
if (yielded == null)
|
||||||
|
{
|
||||||
|
// yield null 意味着等待一帧,但协程可能还没有完成
|
||||||
|
// 需要再次检查是否还有更多步骤
|
||||||
|
bool stillHasNext = current.MoveNext();
|
||||||
|
if (!stillHasNext)
|
||||||
|
{
|
||||||
|
// 协程确实完成了
|
||||||
_stack.Pop();
|
_stack.Pop();
|
||||||
|
if (_stack.Count == 0)
|
||||||
|
{
|
||||||
|
Complete();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 还有更多内容,yield 出来的值需要处理
|
||||||
|
yielded = current.Current;
|
||||||
|
needsWait = ProcessYieldValue(yielded);
|
||||||
|
if (needsWait)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -146,15 +198,11 @@ public class CoroutineHandle : IYieldInstruction, ICoroutineHandle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_stack.Count == 0)
|
// 栈为空,协程完成
|
||||||
{
|
|
||||||
Complete();
|
Complete();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理协程中yield返回的值,根据类型决定如何处理
|
/// 处理协程中yield返回的值,根据类型决定如何处理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -165,25 +213,31 @@ public class CoroutineHandle : IYieldInstruction, ICoroutineHandle
|
|||||||
switch (yielded)
|
switch (yielded)
|
||||||
{
|
{
|
||||||
case CoroutineHandle otherHandle:
|
case CoroutineHandle otherHandle:
|
||||||
// 标记子协程由父协程管理
|
// 处理 yield return CoroutineHandle
|
||||||
if (!otherHandle.IsDone)
|
if (otherHandle.IsDone)
|
||||||
{
|
{
|
||||||
|
// 子协程已完成,不需要等待
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记子协程由父协程管理
|
||||||
otherHandle.MarkAsManagedByParent();
|
otherHandle.MarkAsManagedByParent();
|
||||||
_waitingInstruction = otherHandle;
|
_waitingInstruction = otherHandle;
|
||||||
return true; // 需要等待子协程完成
|
return true; // 需要等待子协程完成
|
||||||
}
|
|
||||||
return false; // 子协程已完成,不需要等待
|
|
||||||
|
|
||||||
case IEnumerator nested:
|
case IEnumerator nested:
|
||||||
|
// 处理 yield return IEnumerator(嵌套协程)
|
||||||
_stack.Push(nested);
|
_stack.Push(nested);
|
||||||
return false; // 压入嵌套协程,立即执行
|
return false; // 压入嵌套协程,在下一帧继续执行
|
||||||
|
|
||||||
case IYieldInstruction instruction:
|
case IYieldInstruction instruction:
|
||||||
|
// 处理 yield return IYieldInstruction
|
||||||
_waitingInstruction = instruction;
|
_waitingInstruction = instruction;
|
||||||
return true; // 需要等待指令完成
|
return true; // 需要等待指令完成
|
||||||
|
|
||||||
case null:
|
case null:
|
||||||
return false; // null,立即继续
|
// 处理 yield return null(等待一帧)
|
||||||
|
return false; // null 立即继续,但会返回 true 让协程继续执行
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException($"Unsupported yield type: {yielded.GetType()}");
|
throw new InvalidOperationException($"Unsupported yield type: {yielded.GetType()}");
|
||||||
|
|||||||
@ -25,16 +25,19 @@ public class CoroutineScheduler : ICoroutineScheduler
|
|||||||
$"Owner: {_ownerThreadId}, Current: {Thread.CurrentThread.ManagedThreadId}");
|
$"Owner: {_ownerThreadId}, Current: {Thread.CurrentThread.ManagedThreadId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 先将新协程添加到活动列表
|
||||||
if (_toAdd.Count > 0)
|
if (_toAdd.Count > 0)
|
||||||
{
|
{
|
||||||
_active.AddRange(_toAdd);
|
_active.AddRange(_toAdd);
|
||||||
_toAdd.Clear();
|
_toAdd.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 遍历活动协程,每帧只推进一步
|
||||||
for (var i = _active.Count - 1; i >= 0; i--)
|
for (var i = _active.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var c = _active[i];
|
var c = _active[i];
|
||||||
|
|
||||||
|
// 检查作用域是否仍然活跃
|
||||||
if (!c.Context.Scope.IsActive)
|
if (!c.Context.Scope.IsActive)
|
||||||
{
|
{
|
||||||
c.Cancel();
|
c.Cancel();
|
||||||
@ -46,21 +49,29 @@ public class CoroutineScheduler : ICoroutineScheduler
|
|||||||
if (c.IsManagedByParent)
|
if (c.IsManagedByParent)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// 更新协程,每帧只推进一步
|
||||||
((IYieldInstruction)c).Update(deltaTime);
|
((IYieldInstruction)c).Update(deltaTime);
|
||||||
|
|
||||||
|
// 如果协程完成,标记为待移除
|
||||||
if (c.IsDone)
|
if (c.IsDone)
|
||||||
_toRemove.Add(c);
|
_toRemove.Add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_toRemove.Count <= 0) return;
|
// 移除已完成的协程
|
||||||
|
if (_toRemove.Count > 0)
|
||||||
|
{
|
||||||
_active.RemoveAll(c => _toRemove.Contains(c));
|
_active.RemoveAll(c => _toRemove.Contains(c));
|
||||||
_toRemove.Clear();
|
_toRemove.Clear();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal CoroutineHandle StartCoroutine(IEnumerator routine, CoroutineContext context)
|
internal CoroutineHandle StartCoroutine(IEnumerator routine, CoroutineContext context)
|
||||||
{
|
{
|
||||||
var handle = new CoroutineHandle(routine, context, null);
|
var handle = new CoroutineHandle(routine, context, null);
|
||||||
|
|
||||||
|
// 添加到调度队列,协程将在下次 Update 时开始执行
|
||||||
_toAdd.Add(handle);
|
_toAdd.Add(handle);
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,7 @@ public static class CoroutineScopeExtensions
|
|||||||
{
|
{
|
||||||
yield return new WaitForSeconds(delay);
|
yield return new WaitForSeconds(delay);
|
||||||
action?.Invoke();
|
action?.Invoke();
|
||||||
|
yield break; // 确保协程正确结束
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -52,11 +53,11 @@ public static class CoroutineScopeExtensions
|
|||||||
/// <returns>协程迭代器</returns>
|
/// <returns>协程迭代器</returns>
|
||||||
private static IEnumerator RepeatingRoutine(float interval, Action action)
|
private static IEnumerator RepeatingRoutine(float interval, Action action)
|
||||||
{
|
{
|
||||||
// 持续循环执行动作并等待指定间隔
|
// 持续循环等待指定间隔后执行动作
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
action?.Invoke();
|
|
||||||
yield return new WaitForSeconds(interval);
|
yield return new WaitForSeconds(interval);
|
||||||
|
action?.Invoke(); // 先等待,再执行
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ public class WaitUntil(Func<bool> predicate) : IYieldInstruction
|
|||||||
/// <param name="deltaTime">时间增量</param>
|
/// <param name="deltaTime">时间增量</param>
|
||||||
public void Update(float deltaTime)
|
public void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
// 只有在未完成状态下才检查条件
|
// 每次更新都重新评估条件,但一旦完成就保持完成状态
|
||||||
if (!IsDone) IsDone = predicate();
|
if (!IsDone) IsDone = predicate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user