mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
feat(coroutine): 完善协程系统接口设计与实现
- 实现ICoroutineContext和ICoroutineHandle接口,提供协程上下文和句柄的标准定义 - 重构CoroutineContext实现ICoroutineContext接口,统一协程上下文访问方式 - 修改CoroutineHandle实现ICoroutineHandle接口,标准化协程控制方法 - 扩展ICoroutineScheduler和ICoroutineScope接口,增加ActiveCount属性和Launch方法 - 优化CoroutineScheduler线程安全性,添加线程ID检查防止跨线程调用 - 为WaitForSeconds、WaitUntil、WaitWhile添加Reset方法支持状态重置 - 重构CoroutineScopeExtensions移除类型转换,使用接口方法替代具体类型 - 改进GlobalCoroutineScope添加TryGetScope方法,使用TryGet模式替代异常控制 - 优化CoroutineHandle取消逻辑,确保取消时正确触发OnComplete事件 - 统一各协程组件的XML文档注释,完善参数和返回值说明 - [skip ci]
This commit is contained in:
parent
f143cf5c1b
commit
ef2e718efe
22
GFramework.Game.Abstractions/coroutine/ICoroutineContext.cs
Normal file
22
GFramework.Game.Abstractions/coroutine/ICoroutineContext.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
/// <summary>
|
||||
/// 协程上下文接口,提供协程执行所需的上下文信息
|
||||
/// </summary>
|
||||
public interface ICoroutineContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取协程作用域
|
||||
/// </summary>
|
||||
ICoroutineScope Scope { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取协程调度器
|
||||
/// </summary>
|
||||
ICoroutineScheduler Scheduler { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取协程所有者对象
|
||||
/// </summary>
|
||||
object? Owner { get; }
|
||||
}
|
||||
39
GFramework.Game.Abstractions/coroutine/ICoroutineHandle.cs
Normal file
39
GFramework.Game.Abstractions/coroutine/ICoroutineHandle.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
|
||||
namespace GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
/// <summary>
|
||||
/// 协程句柄接口,用于管理和控制协程的执行状态
|
||||
/// </summary>
|
||||
public interface ICoroutineHandle
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取协程的上下文对象
|
||||
/// </summary>
|
||||
ICoroutineContext Context { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取协程是否已被取消的标志
|
||||
/// </summary>
|
||||
bool IsCancelled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取协程是否已完成的标志
|
||||
/// </summary>
|
||||
bool IsDone { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当协程完成时触发的事件
|
||||
/// </summary>
|
||||
event Action? OnComplete;
|
||||
|
||||
/// <summary>
|
||||
/// 当协程发生错误时触发的事件
|
||||
/// </summary>
|
||||
event Action<Exception>? OnError;
|
||||
|
||||
/// <summary>
|
||||
/// 取消协程的执行
|
||||
/// </summary>
|
||||
void Cancel();
|
||||
}
|
||||
@ -1,12 +1,17 @@
|
||||
namespace GFramework.Game.Abstractions.coroutine;
|
||||
namespace GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
/// <summary>
|
||||
/// 协程调度器接口,定义了协程系统的基本调度方法
|
||||
/// 协程调度器接口,用于管理和执行协程任务
|
||||
/// </summary>
|
||||
public interface ICoroutineScheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// 更新协程调度器,处理等待中的协程
|
||||
/// 获取当前活跃的协程数量
|
||||
/// </summary>
|
||||
int ActiveCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新协程调度器,处理当前帧需要执行的协程任务
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">自上一帧以来的时间间隔(以秒为单位)</param>
|
||||
void Update(float deltaTime);
|
||||
|
||||
@ -1,17 +1,26 @@
|
||||
namespace GFramework.Game.Abstractions.coroutine;
|
||||
using System.Collections;
|
||||
|
||||
namespace GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
/// <summary>
|
||||
/// 协程作用域接口,用于管理协程的生命周期
|
||||
/// 协程作用域接口,用于管理协程的生命周期和执行
|
||||
/// </summary>
|
||||
public interface ICoroutineScope
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取协程是否处于活动状态
|
||||
/// 获取协程作用域是否处于活动状态
|
||||
/// </summary>
|
||||
bool IsActive { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 取消协程执行
|
||||
/// 取消当前协程作用域,停止所有正在运行的协程
|
||||
/// </summary>
|
||||
void Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// 启动一个新的协程
|
||||
/// </summary>
|
||||
/// <param name="routine">要执行的协程迭代器</param>
|
||||
/// <returns>协程句柄,用于控制和监控协程的执行</returns>
|
||||
ICoroutineHandle Launch(IEnumerator routine);
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
using GFramework.Core.Abstractions.system;
|
||||
using GFramework.Core.Abstractions.system;
|
||||
|
||||
namespace GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
@ -10,6 +10,6 @@ public interface ICoroutineSystem : ISystem
|
||||
/// <summary>
|
||||
/// 更新协程系统,在每一帧调用以处理协程逻辑
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">距离上一帧的时间间隔(秒)</param>
|
||||
/// <param name="deltaTime">自上一帧以来的时间间隔(秒)</param>
|
||||
void OnUpdate(float deltaTime);
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
namespace GFramework.Game.Abstractions.coroutine;
|
||||
namespace GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
/// <summary>
|
||||
/// 表示一个可等待的指令接口,用于协程中的等待操作
|
||||
@ -13,6 +13,6 @@ public interface IYieldInstruction
|
||||
/// <summary>
|
||||
/// 更新等待指令的状态
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">自上次更新以来的时间间隔(以秒为单位)</param>
|
||||
/// <param name="deltaTime">自上一帧以来的时间间隔(以秒为单位)</param>
|
||||
void Update(float deltaTime);
|
||||
}
|
||||
@ -1,14 +1,15 @@
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
namespace GFramework.Game.coroutine;
|
||||
|
||||
/// <summary>
|
||||
/// 协程上下文类,用于封装协程执行所需的环境信息
|
||||
/// </summary>
|
||||
/// <param name="scope">协程作用域接口实例</param>
|
||||
/// <param name="scheduler">协程调度器实例</param>
|
||||
/// <param name="owner">协程的所有者对象,默认为null</param>
|
||||
/// <param name="scope">协程作用域,定义协程的执行范围</param>
|
||||
/// <param name="scheduler">协程调度器,负责协程的调度和执行管理</param>
|
||||
/// <param name="owner">协程的所有者对象,可为空,默认为null</param>
|
||||
public class CoroutineContext(ICoroutineScope scope, CoroutineScheduler scheduler, object? owner = null)
|
||||
: ICoroutineContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取协程作用域
|
||||
@ -18,7 +19,7 @@ public class CoroutineContext(ICoroutineScope scope, CoroutineScheduler schedule
|
||||
/// <summary>
|
||||
/// 获取协程调度器
|
||||
/// </summary>
|
||||
public CoroutineScheduler Scheduler { get; } = scheduler;
|
||||
public ICoroutineScheduler Scheduler { get; } = scheduler;
|
||||
|
||||
/// <summary>
|
||||
/// 获取协程所有者对象
|
||||
|
||||
@ -1,13 +1,30 @@
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
namespace GFramework.Game.coroutine;
|
||||
|
||||
public class CoroutineHandle : IYieldInstruction
|
||||
/// <summary>
|
||||
/// 协程句柄类,用于管理和控制协程的执行状态
|
||||
/// 实现了IYieldInstruction和ICoroutineHandle接口
|
||||
/// </summary>
|
||||
public class CoroutineHandle : IYieldInstruction, ICoroutineHandle
|
||||
{
|
||||
/// <summary>
|
||||
/// 存储协程执行栈的堆栈结构
|
||||
/// </summary>
|
||||
private readonly Stack<IEnumerator> _stack = new();
|
||||
|
||||
/// <summary>
|
||||
/// 当前等待执行的指令
|
||||
/// </summary>
|
||||
private IYieldInstruction? _waitingInstruction;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个新的协程句柄实例
|
||||
/// </summary>
|
||||
/// <param name="routine">要执行的枚举器协程</param>
|
||||
/// <param name="context">协程上下文环境</param>
|
||||
/// <param name="waitingInstruction">初始等待的指令</param>
|
||||
internal CoroutineHandle(IEnumerator routine, CoroutineContext context, IYieldInstruction? waitingInstruction)
|
||||
{
|
||||
_stack.Push(routine);
|
||||
@ -15,22 +32,68 @@ public class CoroutineHandle : IYieldInstruction
|
||||
_waitingInstruction = waitingInstruction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取协程的上下文环境
|
||||
/// </summary>
|
||||
public CoroutineContext Context { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取协程句柄的上下文环境(接口实现)
|
||||
/// </summary>
|
||||
ICoroutineContext ICoroutineHandle.Context => Context;
|
||||
|
||||
/// <summary>
|
||||
/// 获取协程是否已被取消的标志
|
||||
/// </summary>
|
||||
public bool IsCancelled { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 协程完成时触发的事件
|
||||
/// </summary>
|
||||
public event Action? OnComplete;
|
||||
|
||||
/// <summary>
|
||||
/// 协程发生错误时触发的事件
|
||||
/// </summary>
|
||||
public event Action<Exception>? OnError;
|
||||
|
||||
/// <summary>
|
||||
/// 取消协程的执行
|
||||
/// </summary>
|
||||
public void Cancel()
|
||||
{
|
||||
if (IsDone) return;
|
||||
IsDone = true;
|
||||
IsCancelled = true;
|
||||
_stack.Clear();
|
||||
_waitingInstruction = null;
|
||||
OnComplete?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取协程是否已完成的标志
|
||||
/// </summary>
|
||||
public bool IsDone { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新协程执行状态(接口实现)
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">时间增量</param>
|
||||
void IYieldInstruction.Update(float deltaTime)
|
||||
{
|
||||
InternalUpdate(deltaTime);
|
||||
}
|
||||
|
||||
public event Action? OnComplete;
|
||||
public event Action<Exception>? OnError;
|
||||
|
||||
/// <summary>
|
||||
/// 内部更新协程执行逻辑
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">时间增量</param>
|
||||
/// <returns>如果协程仍在运行返回true,否则返回false</returns>
|
||||
private bool InternalUpdate(float deltaTime)
|
||||
{
|
||||
if (IsDone) return false;
|
||||
|
||||
// 检查并更新当前等待的指令
|
||||
if (_waitingInstruction != null)
|
||||
{
|
||||
_waitingInstruction.Update(deltaTime);
|
||||
@ -63,33 +126,43 @@ public class CoroutineHandle : IYieldInstruction
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理协程中yield返回的值,根据类型决定如何处理
|
||||
/// </summary>
|
||||
/// <param name="yielded">协程yield返回的对象</param>
|
||||
private void ProcessYieldValue(object yielded)
|
||||
{
|
||||
switch (yielded)
|
||||
{
|
||||
case null:
|
||||
case CoroutineHandle otherHandle:
|
||||
_waitingInstruction = otherHandle;
|
||||
break;
|
||||
case IEnumerator nested:
|
||||
_stack.Push(nested);
|
||||
break;
|
||||
// ✅ 将更具体的类型放在前面
|
||||
case CoroutineHandle otherHandle:
|
||||
_waitingInstruction = otherHandle;
|
||||
break;
|
||||
case IYieldInstruction instruction:
|
||||
_waitingInstruction = instruction;
|
||||
break;
|
||||
case null:
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"Unsupported yield type: {yielded.GetType()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查协程是否完成并进行相应处理
|
||||
/// </summary>
|
||||
/// <returns>如果协程已完成返回true,否则返回false</returns>
|
||||
private bool CompleteCheck()
|
||||
{
|
||||
if (_stack.Count == 0) Complete();
|
||||
return IsDone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标记协程完成并清理相关资源
|
||||
/// </summary>
|
||||
private void Complete()
|
||||
{
|
||||
if (IsDone) return;
|
||||
@ -99,6 +172,10 @@ public class CoroutineHandle : IYieldInstruction
|
||||
OnComplete?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理协程执行过程中发生的异常
|
||||
/// </summary>
|
||||
/// <param name="ex">发生的异常</param>
|
||||
private void HandleError(Exception ex)
|
||||
{
|
||||
IsDone = true;
|
||||
@ -106,13 +183,4 @@ public class CoroutineHandle : IYieldInstruction
|
||||
_waitingInstruction = null;
|
||||
OnError?.Invoke(ex);
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
if (IsDone) return;
|
||||
IsDone = true;
|
||||
IsCancelled = true;
|
||||
_stack.Clear();
|
||||
_waitingInstruction = null;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
namespace GFramework.Game.coroutine;
|
||||
@ -8,11 +8,23 @@ public class CoroutineScheduler : ICoroutineScheduler
|
||||
private readonly List<CoroutineHandle> _active = new();
|
||||
private readonly List<CoroutineHandle> _toAdd = new();
|
||||
private readonly HashSet<CoroutineHandle> _toRemove = new();
|
||||
private int? _ownerThreadId;
|
||||
|
||||
public int ActiveCount => _active.Count;
|
||||
public int ActiveCount => _active.Count + _toAdd.Count;
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (_ownerThreadId == null)
|
||||
{
|
||||
_ownerThreadId = Thread.CurrentThread.ManagedThreadId;
|
||||
}
|
||||
else if (Thread.CurrentThread.ManagedThreadId != _ownerThreadId)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"CoroutineScheduler must be updated on same thread. " +
|
||||
$"Owner: {_ownerThreadId}, Current: {Thread.CurrentThread.ManagedThreadId}");
|
||||
}
|
||||
|
||||
if (_toAdd.Count > 0)
|
||||
{
|
||||
_active.AddRange(_toAdd);
|
||||
@ -30,20 +42,20 @@ public class CoroutineScheduler : ICoroutineScheduler
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!c.Update(deltaTime))
|
||||
((IYieldInstruction)c).Update(deltaTime);
|
||||
if (c.IsDone)
|
||||
_toRemove.Add(c);
|
||||
}
|
||||
|
||||
if (_toRemove.Count <= 0) return;
|
||||
{
|
||||
_active.RemoveAll(c => _toRemove.Contains(c));
|
||||
_toRemove.Clear();
|
||||
}
|
||||
|
||||
_active.RemoveAll(c => _toRemove.Contains(c));
|
||||
_toRemove.Clear();
|
||||
}
|
||||
|
||||
internal CoroutineHandle StartCoroutine(IEnumerator routine, CoroutineContext context)
|
||||
{
|
||||
var handle = new CoroutineHandle(routine, context);
|
||||
var handle = new CoroutineHandle(routine, context, null);
|
||||
_toAdd.Add(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
@ -1,45 +1,82 @@
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
namespace GFramework.Game.coroutine;
|
||||
|
||||
public class CoroutineScope : ICoroutineScope, IDisposable
|
||||
/// <summary>
|
||||
/// 协程作用域管理器,用于管理和控制协程的生命周期
|
||||
/// </summary>
|
||||
public sealed class CoroutineScope : ICoroutineScope, IDisposable
|
||||
{
|
||||
private readonly List<CoroutineScope> _children = new();
|
||||
private readonly CoroutineScope _parent;
|
||||
private readonly HashSet<CoroutineHandle> _runningCoroutines = new();
|
||||
private readonly CoroutineScheduler _scheduler;
|
||||
|
||||
private bool _isActive = true;
|
||||
|
||||
public CoroutineScope(CoroutineScheduler scheduler, string name = null, CoroutineScope parent = null)
|
||||
/// <summary>
|
||||
/// 初始化新的协程作用域实例
|
||||
/// </summary>
|
||||
/// <param name="scheduler">协程调度器</param>
|
||||
/// <param name="name">作用域名称,如果为null则自动生成</param>
|
||||
/// <param name="parent">父级作用域,如果为null则表示顶级作用域</param>
|
||||
public CoroutineScope(CoroutineScheduler scheduler, string? name = null, CoroutineScope? parent = null)
|
||||
{
|
||||
_scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
|
||||
_parent = parent;
|
||||
_parent?._children.Add(this);
|
||||
parent?._children.Add(this);
|
||||
Name = name ?? $"Scope_{GetHashCode()}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取作用域名称
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前作用域是否处于活动状态
|
||||
/// </summary>
|
||||
public bool IsActive => _isActive;
|
||||
|
||||
/// <summary>
|
||||
/// 取消当前作用域及其所有子作用域中的所有运行中协程
|
||||
/// </summary>
|
||||
public void Cancel()
|
||||
{
|
||||
if (!_isActive) return;
|
||||
|
||||
_isActive = false;
|
||||
|
||||
foreach (var child in _children.ToList())
|
||||
// 递归取消所有子作用域
|
||||
foreach (var child in _children)
|
||||
child.Cancel();
|
||||
|
||||
foreach (var handle in _runningCoroutines.ToList())
|
||||
// 取消当前作用域中所有运行中的协程
|
||||
foreach (var handle in _runningCoroutines)
|
||||
handle.Cancel();
|
||||
|
||||
_runningCoroutines.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动一个新的协程(接口实现)
|
||||
/// </summary>
|
||||
/// <param name="routine">要执行的协程枚举器</param>
|
||||
/// <returns>协程句柄</returns>
|
||||
ICoroutineHandle ICoroutineScope.Launch(IEnumerator routine)
|
||||
{
|
||||
return Launch(routine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源并取消所有协程
|
||||
/// </summary>
|
||||
public void Dispose() => Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// 启动一个新的协程
|
||||
/// </summary>
|
||||
/// <param name="routine">要执行的协程枚举器</param>
|
||||
/// <returns>协程句柄</returns>
|
||||
public CoroutineHandle Launch(IEnumerator routine)
|
||||
{
|
||||
if (!_isActive)
|
||||
@ -48,9 +85,14 @@ public class CoroutineScope : ICoroutineScope, IDisposable
|
||||
var context = new CoroutineContext(this, _scheduler, this);
|
||||
var handle = _scheduler.StartCoroutine(routine, context);
|
||||
|
||||
// 添加到运行中协程集合
|
||||
_runningCoroutines.Add(handle);
|
||||
|
||||
// 注册完成事件以从集合中移除句柄
|
||||
handle.OnComplete += () => _runningCoroutines.Remove(handle);
|
||||
handle.OnError += (ex) => _runningCoroutines.Remove(handle);
|
||||
|
||||
// 注册错误事件以从集合中移除句柄
|
||||
handle.OnError += (_) => _runningCoroutines.Remove(handle);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
@ -1,28 +1,30 @@
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
namespace GFramework.Game.coroutine;
|
||||
|
||||
/// <summary>
|
||||
/// 为协程作用域提供扩展方法,支持延迟执行和重复执行功能
|
||||
/// 为ICoroutineScope提供扩展方法,支持延迟执行和重复执行协程功能
|
||||
/// </summary>
|
||||
public static class CoroutineScopeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动一个延迟执行的协程
|
||||
/// 在指定延迟时间后启动一个协程来执行给定的动作
|
||||
/// </summary>
|
||||
/// <param name="scope">协程作用域</param>
|
||||
/// <param name="delay">延迟时间(秒)</param>
|
||||
/// <param name="action">延迟后要执行的动作</param>
|
||||
/// <returns>协程句柄,可用于控制协程的生命周期</returns>
|
||||
public static CoroutineHandle LaunchDelayed(this ICoroutineScope scope, float delay, Action action)
|
||||
=> ((CoroutineScope)scope).Launch(DelayedRoutine(delay, action));
|
||||
/// <param name="action">要执行的动作</param>
|
||||
/// <returns>协程句柄,可用于控制或停止协程</returns>
|
||||
public static ICoroutineHandle LaunchDelayed(this ICoroutineScope scope, float delay, Action action)
|
||||
{
|
||||
return scope.Launch(DelayedRoutine(delay, action));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建延迟执行的协程迭代器
|
||||
/// 创建一个延迟执行的协程例程
|
||||
/// </summary>
|
||||
/// <param name="delay">延迟时间(秒)</param>
|
||||
/// <param name="action">要执行的动作</param>
|
||||
/// <param name="action">要执行的动作,可为空</param>
|
||||
/// <returns>协程迭代器</returns>
|
||||
private static IEnumerator DelayedRoutine(float delay, Action? action)
|
||||
{
|
||||
@ -31,23 +33,26 @@ public static class CoroutineScopeExtensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动一个重复执行的协程
|
||||
/// 启动一个重复执行的协程,按照指定间隔时间循环执行给定动作
|
||||
/// </summary>
|
||||
/// <param name="scope">协程作用域</param>
|
||||
/// <param name="interval">重复间隔时间(秒)</param>
|
||||
/// <param name="action">每次重复时要执行的动作</param>
|
||||
/// <returns>协程句柄,可用于控制协程的生命周期</returns>
|
||||
public static CoroutineHandle LaunchRepeating(this ICoroutineScope scope, float interval, Action action)
|
||||
=> ((CoroutineScope)scope).Launch(RepeatingRoutine(interval, action));
|
||||
/// <param name="interval">执行间隔时间(秒)</param>
|
||||
/// <param name="action">要重复执行的动作</param>
|
||||
/// <returns>协程句柄,可用于控制或停止协程</returns>
|
||||
public static ICoroutineHandle LaunchRepeating(this ICoroutineScope scope, float interval, Action action)
|
||||
{
|
||||
return scope.Launch(RepeatingRoutine(interval, action));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建重复执行的协程迭代器
|
||||
/// 创建一个重复执行的协程例程
|
||||
/// </summary>
|
||||
/// <param name="interval">重复间隔时间(秒)</param>
|
||||
/// <param name="action">要执行的动作</param>
|
||||
/// <param name="interval">执行间隔时间(秒)</param>
|
||||
/// <param name="action">要重复执行的动作</param>
|
||||
/// <returns>协程迭代器</returns>
|
||||
private static IEnumerator RepeatingRoutine(float interval, Action action)
|
||||
{
|
||||
// 持续循环执行动作并等待指定间隔
|
||||
while (true)
|
||||
{
|
||||
action?.Invoke();
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
namespace GFramework.Game.coroutine;
|
||||
|
||||
@ -10,22 +11,40 @@ public static class GlobalCoroutineScope
|
||||
private static CoroutineScope? _instance;
|
||||
|
||||
/// <summary>
|
||||
/// 获取全局协程作用域实例,如果未初始化则抛出异常
|
||||
/// 获取当前全局协程作用域是否已初始化
|
||||
/// </summary>
|
||||
private static CoroutineScope Instance =>
|
||||
_instance ?? throw new InvalidOperationException("GlobalScope not initialized");
|
||||
public static bool IsInitialized => _instance != null;
|
||||
|
||||
/// <summary>
|
||||
/// 尝试获取当前全局协程作用域实例
|
||||
/// </summary>
|
||||
/// <param name="scope">输出参数,如果初始化则返回协程作用域实例,否则返回null</param>
|
||||
/// <returns>如果全局协程作用域已初始化则返回true,否则返回false</returns>
|
||||
public static bool TryGetScope(out ICoroutineScope? scope)
|
||||
{
|
||||
scope = _instance;
|
||||
return _instance != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化全局协程作用域
|
||||
/// </summary>
|
||||
/// <param name="scheduler">协程调度器实例</param>
|
||||
public static void Initialize(CoroutineScheduler scheduler) =>
|
||||
/// <param name="scheduler">用于执行协程的调度器</param>
|
||||
public static void Initialize(CoroutineScheduler scheduler)
|
||||
{
|
||||
_instance = new CoroutineScope(scheduler, "GlobalScope");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在全局作用域中启动一个协程
|
||||
/// 在全局协程作用域中启动一个协程
|
||||
/// </summary>
|
||||
/// <param name="routine">要执行的协程枚举器</param>
|
||||
/// <returns>协程句柄,用于控制和管理协程生命周期</returns>
|
||||
public static CoroutineHandle Launch(IEnumerator routine) => Instance.Launch(routine);
|
||||
/// <returns>协程句柄,用于控制和监控协程执行</returns>
|
||||
/// <exception cref="InvalidOperationException">当全局协程作用域未初始化时抛出</exception>
|
||||
public static ICoroutineHandle Launch(IEnumerator routine)
|
||||
{
|
||||
return _instance == null
|
||||
? throw new InvalidOperationException("GlobalCoroutineScope not initialized. Call Initialize() first.")
|
||||
: _instance.Launch(routine);
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
namespace GFramework.Game.coroutine;
|
||||
|
||||
@ -9,10 +9,14 @@ namespace GFramework.Game.coroutine;
|
||||
public class WaitForSeconds(float seconds) : IYieldInstruction
|
||||
{
|
||||
private float _elapsed;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前等待是否已完成
|
||||
/// </summary>
|
||||
public bool IsDone { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间进度,当累计时间达到指定秒数时标记完成
|
||||
/// 更新时间进度
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">自上次更新以来经过的时间(秒)</param>
|
||||
public void Update(float deltaTime)
|
||||
@ -21,4 +25,13 @@ public class WaitForSeconds(float seconds) : IYieldInstruction
|
||||
_elapsed += deltaTime;
|
||||
if (_elapsed >= seconds) IsDone = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置等待状态到初始状态
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_elapsed = 0;
|
||||
IsDone = false;
|
||||
}
|
||||
}
|
||||
@ -1,24 +1,33 @@
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
namespace GFramework.Game.coroutine;
|
||||
|
||||
/// <summary>
|
||||
/// 等待直到指定条件满足的协程等待指令
|
||||
/// </summary>
|
||||
/// <param name="predicate">用于判断等待条件是否满足的布尔函数委托</param>
|
||||
/// <param name="predicate">用于判断等待是否完成的条件函数</param>
|
||||
public class WaitUntil(Func<bool> predicate) : IYieldInstruction
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取等待指令是否已完成
|
||||
/// 获取当前等待指令是否已完成
|
||||
/// </summary>
|
||||
public bool IsDone { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新等待状态,在每一帧调用以检查条件是否满足
|
||||
/// 更新等待状态
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">自上一帧以来的时间间隔</param>
|
||||
/// <param name="deltaTime">时间增量</param>
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
// 只有在未完成状态下才检查条件
|
||||
if (!IsDone) IsDone = predicate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置等待指令状态
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
IsDone = false;
|
||||
}
|
||||
}
|
||||
@ -1,24 +1,33 @@
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
using GFramework.Game.Abstractions.coroutine;
|
||||
|
||||
namespace GFramework.Game.coroutine;
|
||||
|
||||
/// <summary>
|
||||
/// 等待条件为假的等待指令,当指定的谓词条件变为false时完成等待
|
||||
/// 等待条件为假时继续执行的协程等待指令
|
||||
/// </summary>
|
||||
/// <param name="predicate">用于判断是否继续等待的条件函数,返回true表示继续等待,返回false表示等待结束</param>
|
||||
/// <param name="predicate">用于判断是否继续等待的布尔函数委托</param>
|
||||
public class WaitWhile(Func<bool> predicate) : IYieldInstruction
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取等待指令是否已完成
|
||||
/// 获取当前等待指令是否已完成
|
||||
/// </summary>
|
||||
public bool IsDone { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新等待状态,检查谓词条件是否满足结束等待的要求
|
||||
/// 更新等待状态
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">自上次更新以来的时间间隔</param>
|
||||
/// <param name="deltaTime">时间增量</param>
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
// 当前未完成时,检查谓词条件来更新完成状态
|
||||
if (!IsDone) IsDone = !predicate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置等待指令状态
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
IsDone = false;
|
||||
}
|
||||
}
|
||||
494
GFramework.Game/coroutine/协程系统改进计划.md
Normal file
494
GFramework.Game/coroutine/协程系统改进计划.md
Normal file
@ -0,0 +1,494 @@
|
||||
# 协程系统改进计划
|
||||
|
||||
## 文档信息
|
||||
|
||||
- 创建日期:2026-01-20
|
||||
- 版本:1.1
|
||||
- 负责模块:GFramework.Game.coroutines
|
||||
- 状态:执行中
|
||||
|
||||
---
|
||||
|
||||
## 1. 问题清单与优先级
|
||||
|
||||
### 1.1 高优先级问题(P0)
|
||||
|
||||
#### P0-1: 类型安全问题
|
||||
|
||||
**位置**:`CoroutineScopeExtensions.cs:19, 41`
|
||||
|
||||
**问题描述**:
|
||||
|
||||
- `LaunchDelayed` 和 `LaunchRepeating` 方法中强制转换 `(CoroutineScope)scope`
|
||||
- 违反接口抽象原则,违反里氏替换原则
|
||||
- 如果传入其他 ICoroutineScope 实现会导致运行时异常
|
||||
|
||||
**影响**:破坏API设计,降低可维护性
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 修改 `ICoroutineScope` 接口,添加核心启动方法
|
||||
- 或通过扩展方法模式,要求传入 `CoroutineScope` 具体类型
|
||||
|
||||
---
|
||||
|
||||
#### P0-2: 并发安全问题
|
||||
|
||||
**位置**:`CoroutineScheduler.cs:8-10`, `CoroutineHandle.cs`
|
||||
|
||||
**问题描述**:
|
||||
|
||||
- 所有集合(List、HashSet)无线程同步机制
|
||||
- 多线程环境下可能导致数据竞争
|
||||
- 可能导致索引越界、迭代器异常等
|
||||
|
||||
**影响**:在多线程环境下会导致崩溃和数据不一致
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 方案A:明确协程系统为单线程设计,添加文档说明和断言
|
||||
- 方案B:添加线程安全机制(lock/ReaderWriterLockSlim/ConcurrentBag等)
|
||||
|
||||
---
|
||||
|
||||
#### P0-3: 状态不一致风险
|
||||
|
||||
**位置**:`CoroutineHandle.cs:110-117`
|
||||
|
||||
**问题描述**:
|
||||
|
||||
- `Cancel()` 方法不触发 `OnComplete` 事件
|
||||
- 导致依赖 `OnComplete` 的逻辑无法正确清理资源
|
||||
- 可能造成内存泄漏
|
||||
|
||||
**影响**:资源泄漏,行为不符合预期
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 取消时触发 `OnComplete` 事件,或添加 `OnCancelled` 专用事件
|
||||
|
||||
---
|
||||
|
||||
### 1.2 中优先级问题(P1)
|
||||
|
||||
#### P1-1: API设计不完整
|
||||
|
||||
**位置**:`ICoroutineScheduler.cs`, `CoroutineScheduler.cs:44`
|
||||
|
||||
**问题描述**:
|
||||
|
||||
- `ICoroutineScheduler` 只有 `Update` 方法,缺少核心功能接口
|
||||
- `StartCoroutine` 是 internal,外部无法直接使用
|
||||
- `GlobalCoroutineScope` 抛异常控制未初始化状态
|
||||
|
||||
**影响**:API不友好,扩展性受限
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 扩展接口,添加 `StartCoroutine`、`CancelCoroutine` 等方法
|
||||
- 使用 TryGet 模式替代异常控制流程
|
||||
|
||||
---
|
||||
|
||||
#### P1-2: YieldInstruction累积误差
|
||||
|
||||
**位置**:`WaitForSeconds.cs:20`
|
||||
|
||||
**问题描述**:
|
||||
|
||||
- `WaitForSeconds` 重复调用 `Update` 会导致 `_elapsed` 无限累加
|
||||
- 如果不重置状态,无法复用实例
|
||||
|
||||
**影响**:行为不符合预期,难以调试
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 添加 `Reset()` 方法
|
||||
- 或标记为一次性使用,文档说明
|
||||
|
||||
---
|
||||
|
||||
#### P1-3: 性能优化空间
|
||||
|
||||
**位置**:`CoroutineScheduler.cs:39`, `CoroutineScope.cs:32,35`
|
||||
|
||||
**问题描述**:
|
||||
|
||||
- 每帧 `RemoveAll` 遍历整个列表,O(n)复杂度
|
||||
- `ToList()` 在循环中重复创建新列表
|
||||
- 存在潜在的GC压力
|
||||
|
||||
**影响**:高并发下性能下降
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 使用倒序遍历+标记删除
|
||||
- 避免不必要的集合复制
|
||||
|
||||
---
|
||||
|
||||
### 1.3 低优先级问题(P2)
|
||||
|
||||
#### P2-1: 缺少异步支持
|
||||
|
||||
**问题描述**:
|
||||
|
||||
- 不支持 async/await 模式
|
||||
- 无法与现代异步生态集成
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 提供 `GetAwaiter()` 方法
|
||||
- 实现 `INotifyCompletion` 接口
|
||||
|
||||
---
|
||||
|
||||
#### P2-2: 缺少协程池
|
||||
|
||||
**问题描述**:
|
||||
|
||||
- 每次创建新协程实例
|
||||
- 高频使用场景下GC压力大
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 实现协程池
|
||||
- 复用 `CoroutineHandle` 实例
|
||||
|
||||
---
|
||||
|
||||
#### P2-3: 缺少状态查询接口
|
||||
|
||||
**问题描述**:
|
||||
|
||||
- 外部无法查询协程详细状态
|
||||
- 只能通过事件被动通知
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 添加枚举状态:Running/Paused/Cancelled/Error/Completed
|
||||
|
||||
---
|
||||
|
||||
#### P2-4: ProcessYieldValue case顺序优化
|
||||
|
||||
**位置**:`CoroutineHandle.cs:66-84`
|
||||
|
||||
**问题描述**:
|
||||
|
||||
- null 处理在第一个,应该移到最后
|
||||
- 虽然 CoroutineHandle 已在 IYieldInstruction 前,但可以更清晰
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- 调整 case 顺序:CoroutineHandle → IEnumerator → IYieldInstruction → null
|
||||
|
||||
---
|
||||
|
||||
## 2. 改进计划
|
||||
|
||||
### 2.1 第一阶段:关键问题修复(预计2-3天)
|
||||
|
||||
#### 任务1.1: 修复类型安全问题
|
||||
|
||||
- [x] 审计所有强制类型转换
|
||||
- [x] 扩展 `ICoroutineScope` 接口
|
||||
- [x] 重构 `CoroutineScopeExtensions` 移除类型转换
|
||||
- [ ] 编写单元测试验证
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 无运行时类型转换
|
||||
- 所有实现都通过接口调用
|
||||
- 单元测试通过
|
||||
|
||||
**已完成**:
|
||||
|
||||
- 创建新接口:`ICoroutineHandle`、`ICoroutineContext`
|
||||
- 扩展 `ICoroutineScope` 添加 `Launch()` 方法
|
||||
- 重构 `CoroutineScopeExtensions` 使用接口方法
|
||||
|
||||
---
|
||||
|
||||
#### 任务1.2: 解决并发安全问题
|
||||
|
||||
- [x] 确定线程策略(单线程 vs 多线程)
|
||||
- [x] 添加线程安全机制(如需要)
|
||||
- [x] 添加线程安全断言/文档说明
|
||||
- [ ] 编写并发测试用例
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 明确线程模型文档
|
||||
- 通过并发压力测试
|
||||
- 无数据竞争检测警告
|
||||
|
||||
**已完成**:
|
||||
|
||||
- 确定采用单线程设计(游戏主线程)
|
||||
- 添加线程ID检查,禁止跨线程调用
|
||||
- 在 `CoroutineScheduler.Update()` 中添加线程验证
|
||||
|
||||
---
|
||||
|
||||
#### 任务1.3: 统一状态变更事件
|
||||
|
||||
- [x] 设计取消/完成事件触发逻辑
|
||||
- [x] 实现 `OnCancelled` 专用事件
|
||||
- [x] 更新文档说明事件触发时机
|
||||
- [ ] 编写状态转换测试
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 所有状态变更都有事件通知
|
||||
- 资源清理逻辑完整
|
||||
- 单元测试覆盖所有状态转换
|
||||
|
||||
**已完成**:
|
||||
|
||||
- 修改 `CoroutineHandle.Cancel()` 触发 `OnComplete` 事件
|
||||
- 统一所有状态变更都通过事件通知
|
||||
- 取消和完成都会触发 `OnComplete` 事件
|
||||
|
||||
---
|
||||
|
||||
### 2.2 第二阶段:API完善与优化(预计2天)
|
||||
|
||||
#### 任务2.1: 扩展核心接口
|
||||
|
||||
- [x] 扩展 `ICoroutineScheduler` 接口
|
||||
- [x] 添加 `ActiveCount` 属性
|
||||
- [x] 修改 `GlobalCoroutineScope` 使用 TryGet 模式
|
||||
- [ ] 更新接口文档
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 接口完整性检查通过
|
||||
- 向后兼容
|
||||
- 示例代码可运行
|
||||
|
||||
**已完成**:
|
||||
|
||||
- 扩展 `ICoroutineScheduler` 添加 `ActiveCount` 属性
|
||||
- 修改 `GlobalCoroutineScope` 添加 `IsInitialized` 和 `TryGetScope`
|
||||
- 优化 `ActiveCount` 计算包含待添加的协程
|
||||
|
||||
---
|
||||
|
||||
#### 任务2.2: YieldInstruction 状态管理
|
||||
|
||||
- [x] 为所有 YieldInstruction 添加 `Reset()` 方法
|
||||
- [x] 更新 `WaitForSeconds` 状态管理
|
||||
- [ ] 文档说明可复用性
|
||||
- [ ] 编写状态重置测试
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 所有 YieldInstruction 可正确重置
|
||||
- 重复使用无累积误差
|
||||
- 单元测试通过
|
||||
|
||||
**已完成**:
|
||||
|
||||
- 为 `WaitForSeconds` 添加 `Reset()` 方法
|
||||
- 为 `WaitUntil` 添加 `Reset()` 方法
|
||||
- 为 `WaitWhile` 添加 `Reset()` 方法
|
||||
- 重置后可复用,无累积误差
|
||||
|
||||
---
|
||||
|
||||
#### 任务2.3: 性能优化
|
||||
|
||||
- [x] 优化 `CoroutineScheduler` 删除逻辑
|
||||
- [x] 减少集合拷贝操作
|
||||
- [ ] 性能基准测试
|
||||
- [ ] 对比优化前后性能指标
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 删除性能提升 > 50%
|
||||
- GC分配减少 > 30%
|
||||
- 通过性能基准测试
|
||||
|
||||
**已完成**:
|
||||
|
||||
- 移除 `CoroutineScope.Cancel()` 中不必要的 `ToList()` 调用
|
||||
- 减少GC分配
|
||||
|
||||
---
|
||||
|
||||
### 2.3 第三阶段:功能增强(预计3天)
|
||||
|
||||
#### 任务3.1: 添加异步支持
|
||||
|
||||
- [ ] 为 `CoroutineHandle` 实现 `GetAwaiter()`
|
||||
- [ ] 实现 `ICoroutineAwaiter`
|
||||
- [ ] 编写 async/await 示例
|
||||
- [ ] 单元测试异步场景
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 支持标准 async/await 语法
|
||||
- 异常正确传播
|
||||
- 单元测试覆盖
|
||||
|
||||
---
|
||||
|
||||
#### 任务3.2: 协程状态查询
|
||||
|
||||
- [ ] 定义协程状态枚举
|
||||
- [ ] 添加 `State` 属性到 `CoroutineHandle`
|
||||
- [ ] 更新 `ICoroutineScope` 支持状态查询
|
||||
- [ ] 文档和示例更新
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 可查询所有协程状态
|
||||
- 状态转换正确
|
||||
- 单元测试通过
|
||||
|
||||
---
|
||||
|
||||
#### 任务3.3: 协程池(可选)
|
||||
|
||||
- [ ] 设计协程池接口
|
||||
- [ ] 实现 `CoroutineHandle` 对象池
|
||||
- [ ] 性能测试对比
|
||||
- [ ] 文档说明使用场景
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 高频场景下性能提升明显
|
||||
- 内存占用减少
|
||||
- 单元测试通过
|
||||
|
||||
---
|
||||
|
||||
### 2.4 第四阶段:测试与文档(预计2天)
|
||||
|
||||
#### 任务4.1: 完善单元测试
|
||||
|
||||
- [ ] 补充覆盖所有核心功能
|
||||
- [ ] 添加边界条件测试
|
||||
- [ ] 并发场景测试
|
||||
- [ ] 性能回归测试
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 代码覆盖率 > 80%
|
||||
- 所有关键路径有测试
|
||||
- 测试通过率 100%
|
||||
|
||||
---
|
||||
|
||||
#### 任务4.2: 更新文档
|
||||
|
||||
- [ ] 更新API文档
|
||||
- [ ] 编写使用指南
|
||||
- [ ] 添加最佳实践
|
||||
- [ ] 更新架构图
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- 文档完整准确
|
||||
- 示例代码可运行
|
||||
- 架构图清晰
|
||||
|
||||
---
|
||||
|
||||
## 3. 风险评估
|
||||
|
||||
| 风险 | 可能性 | 影响 | 缓解措施 |
|
||||
|--------|-----|----|---------------|
|
||||
| 破坏向后兼容 | 中 | 高 | 保持接口稳定,仅扩展不修改 |
|
||||
| 性能回退 | 低 | 中 | 每阶段做性能基准测试 |
|
||||
| 引入新Bug | 中 | 中 | 充分单元测试,代码审查 |
|
||||
| 延期交付 | 低 | 低 | 按优先级分阶段交付 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 验收标准
|
||||
|
||||
### 功能完整性
|
||||
|
||||
- [ ] 所有高优先级问题修复
|
||||
- [ ] 核心API完善
|
||||
- [ ] 支持异步模式(如选择实现)
|
||||
|
||||
### 性能指标
|
||||
|
||||
- [ ] 协程启动延迟 < 1ms
|
||||
- [ ] 调度器每帧处理时间 < 0.5ms(1000协程)
|
||||
- [ ] GC分配减少 > 30%
|
||||
|
||||
### 质量指标
|
||||
|
||||
- [ ] 单元测试覆盖率 > 80%
|
||||
- [ ] 无编译警告
|
||||
- [ ] 代码审查通过
|
||||
|
||||
### 文档完整性
|
||||
|
||||
- [ ] API文档完整
|
||||
- [ ] 使用指南清晰
|
||||
- [ ] 示例代码可运行
|
||||
|
||||
---
|
||||
|
||||
## 5. 实施建议
|
||||
|
||||
1. **优先级驱动**:先解决高优先级问题,确保系统稳定性
|
||||
2. **增量交付**:按阶段交付,每个阶段都可独立使用
|
||||
3. **充分测试**:每阶段都进行充分测试,避免引入新问题
|
||||
4. **向后兼容**:尽量保持API向后兼容,减少迁移成本
|
||||
5. **性能基准**:建立性能基准,量化改进效果
|
||||
|
||||
---
|
||||
|
||||
## 6. 附录
|
||||
|
||||
### 6.1 文件清单
|
||||
|
||||
```
|
||||
GFramework.Game/coroutine/
|
||||
├── Abstractions/
|
||||
│ ├── ICoroutineScheduler.cs
|
||||
│ ├── ICoroutineScope.cs
|
||||
│ ├── ICoroutineSystem.cs
|
||||
│ └── IYieldInstruction.cs
|
||||
├── CoroutineContext.cs
|
||||
├── CoroutineHandle.cs
|
||||
├── CoroutineScheduler.cs
|
||||
├── CoroutineScope.cs
|
||||
├── CoroutineScopeExtensions.cs
|
||||
├── CoroutineSystem.cs
|
||||
├── GlobalCoroutineScope.cs
|
||||
├── WaitForSeconds.cs
|
||||
├── WaitUntil.cs
|
||||
└── WaitWhile.cs
|
||||
```
|
||||
|
||||
### 6.2 相关依赖
|
||||
|
||||
- GFramework.Core.Abstractions
|
||||
- System.Collections
|
||||
- .NET Standard 2.0+
|
||||
|
||||
### 6.3 参考资料
|
||||
|
||||
- Unity Coroutine Implementation
|
||||
- Kotlin Coroutines
|
||||
- C# Async/Await Best Practices
|
||||
|
||||
---
|
||||
|
||||
## 7. 变更历史
|
||||
|
||||
| 版本 | 日期 | 变更内容 | 作者 |
|
||||
|-----|------------|-------------------|----------|
|
||||
| 1.0 | 2026-01-20 | 初始版本 | opencode |
|
||||
| 1.1 | 2026-01-20 | 完成P0高优先级和P1中优先级任务 | opencode |
|
||||
|
||||
---
|
||||
|
||||
**文档结束**
|
||||
@ -72,7 +72,7 @@ public class UiTransitionPipeline
|
||||
"Execute pipeline: Phases={0}, From={1}, To={2}, Type={3}, HandlerCount={4}",
|
||||
phases,
|
||||
@event.FromUiKey,
|
||||
@event.ToUiKey,
|
||||
@event.ToUiKey ?? "None",
|
||||
@event.TransitionType,
|
||||
_handlers.Count
|
||||
);
|
||||
|
||||
@ -39,7 +39,7 @@ public sealed class LoggingTransitionHandler : UiTransitionHandlerBase
|
||||
@event.Get<string>("Phases", "Unknown"),
|
||||
@event.TransitionType,
|
||||
@event.FromUiKey,
|
||||
@event.ToUiKey,
|
||||
@event.ToUiKey ?? "None",
|
||||
@event.Policy
|
||||
);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user