GeWuYou a79f02c987 docs(api): 添加 Core API 参考文档与事件系统接口文档
- 新增 Core API 参考文档,涵盖架构与模块、数据模型与系统、命令与查询等核心组件
- 添加事件系统接口详细文档,包括 IEvent、IEventBus、IUnRegister 等接口说明
- 提供完整的 API 使用示例路径、最佳实践与性能建议
- 包含架构图、依赖关系图与故障排查指南
- 添加测试用例参考与扩展方法说明
- [skip ci]
2026-01-21 23:45:10 +08:00

22 KiB
Raw Blame History

协程调度器核心

**本文引用的文件** - [CoroutineScheduler.cs](file://GFramework.Core/coroutine/CoroutineScheduler.cs) - [CoroutineHandle.cs](file://GFramework.Core/coroutine/CoroutineHandle.cs) - [CoroutineMetadata.cs](file://GFramework.Core/coroutine/CoroutineMetadata.cs) - [CoroutineSlot.cs](file://GFramework.Core/coroutine/CoroutineSlot.cs) - [WaitForCoroutine.cs](file://GFramework.Core/coroutine/WaitForCoroutine.cs) - [Delay.cs](file://GFramework.Core/coroutine/Delay.cs) - [WaitOneFrame.cs](file://GFramework.Core/coroutine/WaitOneFrame.cs) - [WaitForFrames.cs](file://GFramework.Core/coroutine/WaitForFrames.cs) - [WaitUntil.cs](file://GFramework.Core/coroutine/WaitUntil.cs) - [WaitWhile.cs](file://GFramework.Core/coroutine/WaitWhile.cs) - [CoroutineHelper.cs](file://GFramework.Core/coroutine/CoroutineHelper.cs) - [CoroutineState.cs](file://GFramework.Core.Abstractions/coroutine/CoroutineState.cs) - [IYieldInstruction.cs](file://GFramework.Core.Abstractions/coroutine/IYieldInstruction.cs) - [CoroutineSchedulerTests.cs](file://GFramework.Core.Tests/coroutine/CoroutineSchedulerTests.cs)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件围绕 CoroutineScheduler 核心调度器进行深入技术文档化,重点解释其架构设计、高性能执行引擎实现以及关键方法的工作流程。文档覆盖以下主题:

  • Run 方法的协程启动流程:槽位分配、元数据创建、预热机制
  • Update 方法的协程状态更新循环:等待指令处理、协程推进、异常捕获
  • 协程生命周期管理:暂停(Pause)、恢复(Resume)、终止(Kill)
  • 协程等待机制WaitForCoroutine 的依赖等待与唤醒逻辑
  • 协程标签系统与批量管理
  • 性能优化策略与内存管理最佳实践
  • 实际使用示例与常见问题解决方案

项目结构

该调度器位于 GFramework.Core/coroutine 目录下,配合抽象层接口与若干等待指令实现共同构成协程系统。

graph TB
subgraph "协程系统"
S["CoroutineScheduler.cs"]
H["CoroutineHandle.cs"]
M["CoroutineMetadata.cs"]
L["CoroutineSlot.cs"]
WFC["WaitForCoroutine.cs"]
D["Delay.cs"]
WOF["WaitOneFrame.cs"]
WFF["WaitForFrames.cs"]
WU["WaitUntil.cs"]
WW["WaitWhile.cs"]
CH["CoroutineHelper.cs"]
end
subgraph "抽象层"
CS["CoroutineState.cs"]
YI["IYieldInstruction.cs"]
end
S --> H
S --> M
S --> L
S --> WFC
S --> D
S --> WOF
S --> WFF
S --> WU
S --> WW
S -.-> YI
S -.-> CS
CH --> D
CH --> WOF
CH --> WFF
CH --> WU
CH --> WW

图表来源

章节来源

核心组件

  • 协程调度器 CoroutineScheduler负责协程的创建、更新、暂停/恢复/终止、等待与标签管理、容量扩展与异常处理。
  • 协程句柄 CoroutineHandle唯一标识协程实例支持实例隔离与键值提取。
  • 协程槽位 CoroutineSlot承载单个协程的枚举器、状态与等待指令。
  • 协程元数据 CoroutineMetadata记录槽位索引、状态、标签与活跃性判断。
  • 等待指令 IYieldInstruction 及其实现Delay、WaitOneFrame、WaitForFrames、WaitUntil、WaitWhile、WaitForCoroutine。
  • 协程辅助工具 CoroutineHelper提供常用等待指令的便捷构造方法。

章节来源

架构总览

调度器采用“槽位+元数据”的双映射结构:

  • 槽位数组按顺序存储协程执行上下文,便于 O(1) 遍历与更新。
  • 元数据字典将句柄映射到状态、槽位索引与标签,支持快速查询与状态变更。
  • 等待集合维护“被等待者”到“等待者”的反向依赖,实现唤醒链路。
  • 标签集合支持按标签批量管理协程。
classDiagram
class CoroutineScheduler {
-Dictionary~CoroutineHandle, CoroutineMetadata~ _metadata
-Dictionary~string, HashSet~CoroutineHandle~~ _tagged
-Dictionary~CoroutineHandle, HashSet~CoroutineHandle~~ _waiting
-CoroutineSlot?[] _slots
-int _activeCount
-int _nextSlot
+DeltaTime : double
+ActiveCoroutineCount : int
+Run(coroutine, tag) CoroutineHandle
+Update() void
+Pause(handle) bool
+Resume(handle) bool
+Kill(handle) bool
+WaitForCoroutine(current, target) void
+KillByTag(tag) int
+Clear() int
-Prewarm(slotIndex) void
-Complete(slotIndex) void
-OnError(slotIndex, ex) void
-Expand() void
-AddTag(tag, handle) void
-RemoveTag(handle) void
}
class CoroutineSlot {
+Enumerator : IEnumerator~IYieldInstruction~
+State : CoroutineState
+Waiting : IYieldInstruction?
}
class CoroutineMetadata {
+SlotIndex : int
+State : CoroutineState
+Tag : string?
+IsActive : bool
}
class CoroutineHandle {
+Key : byte
+IsValid : bool
+Equals(other) bool
+GetHashCode() int
}
class IYieldInstruction {
<<interface>>
+IsDone : bool
+Update(deltaTime) void
}
CoroutineScheduler --> CoroutineSlot : "管理"
CoroutineScheduler --> CoroutineMetadata : "映射"
CoroutineScheduler --> CoroutineHandle : "键"
CoroutineSlot --> IYieldInstruction : "持有"

图表来源

详细组件分析

Run 方法:协程启动流程

  • 输入校验:若协程为空,直接返回无效句柄。
  • 槽位扩容:若当前槽位已满,则按倍增策略扩展数组容量。
  • 分配句柄与槽位:生成新的协程句柄,并递增下一个可用槽位索引。
  • 创建槽位:初始化枚举器与运行状态。
  • 创建元数据:记录槽位索引、运行状态与可选标签。
  • 标签注册:若提供标签,加入标签集合。
  • 预热执行:立即推进一次协程,读取首个等待指令;异常将被捕获并完成协程。
  • 活跃计数增加:确保统计准确。
sequenceDiagram
participant Caller as "调用方"
participant Scheduler as "CoroutineScheduler"
participant Slots as "槽位数组"
participant Meta as "元数据字典"
participant Tag as "标签集合"
Caller->>Scheduler : Run(协程, 标签?)
Scheduler->>Scheduler : 检查协程是否为空
alt 协程为空
Scheduler-->>Caller : 返回无效句柄
else 协程非空
Scheduler->>Scheduler : 检查槽位容量并扩展
Scheduler->>Scheduler : 分配新句柄与槽位索引
Scheduler->>Slots : 创建并写入槽位
Scheduler->>Meta : 创建并写入元数据
alt 提供了标签
Scheduler->>Tag : 注册标签
end
Scheduler->>Scheduler : 预热(推进一次)
Scheduler->>Scheduler : 活跃计数+1
Scheduler-->>Caller : 返回句柄
end

图表来源

章节来源

Update 方法:协程状态更新循环

  • 时间源更新:先驱动时间源,获取 DeltaTime。
  • 遍历槽位仅遍历已分配的槽位_nextSlot跳过空槽位与非运行状态。
  • 等待指令处理:若存在等待指令,调用 Update(delta),若未完成则跳过本次推进。
  • 协程推进MoveNext(),若返回 false 则完成协程;否则将当前指令作为等待指令。
  • 异常捕获:任何异常均转交 OnError统一完成协程并输出错误日志。
flowchart TD
Start(["进入 Update"]) --> UpdateTime["更新时间源<br/>获取 DeltaTime"]
UpdateTime --> Loop["遍历槽位 i=0.._nextSlot-1"]
Loop --> CheckSlot{"槽位有效且运行中?"}
CheckSlot --> |否| NextIter["继续下一个槽位"]
CheckSlot --> |是| WaitCheck{"存在等待指令?"}
WaitCheck --> |是| UpdateWait["调用 Waiting.Update(delta)"]
UpdateWait --> WaitDone{"IsDone==true"}
WaitDone --> |否| NextIter
WaitDone --> |是| ClearWait["清空等待指令"]
WaitCheck --> |否| MoveNext["MoveNext()"]
ClearWait --> MoveNext
MoveNext --> Done{"MoveNext 返回?"}
Done --> |否| Complete["Complete(slotIndex)"]
Done --> |是| SetWait["slot.Waiting = 当前指令"]
Complete --> NextIter
SetWait --> NextIter
NextIter --> Loop
Loop --> End(["结束"])

图表来源

章节来源

生命周期管理Pause/Resume/Kill

  • Pause仅对运行中的协程生效将其与元数据同时置为暂停。
  • Resume仅对暂停中的协程生效恢复为运行。
  • Kill直接完成指定槽位的协程触发标签移除与等待者唤醒。
sequenceDiagram
participant Caller as "调用方"
participant Scheduler as "CoroutineScheduler"
participant Slot as "CoroutineSlot"
participant Meta as "CoroutineMetadata"
Caller->>Scheduler : Pause(handle)
Scheduler->>Meta : 查找元数据
alt 元数据存在且槽位有效且运行中
Scheduler->>Slot : 设置为 Paused
Scheduler->>Meta : 设置为 Paused
Scheduler-->>Caller : 返回 true
else 否
Scheduler-->>Caller : 返回 false
end
Caller->>Scheduler : Resume(handle)
Scheduler->>Meta : 查找元数据
alt 元数据存在且槽位有效且暂停中
Scheduler->>Slot : 设置为 Running
Scheduler->>Meta : 设置为 Running
Scheduler-->>Caller : 返回 true
else 否
Scheduler-->>Caller : 返回 false
end
Caller->>Scheduler : Kill(handle)
Scheduler->>Scheduler : Complete(slotIndex)
Scheduler-->>Caller : 返回 true

图表来源

章节来源

等待机制WaitForCoroutine 依赖等待与唤醒

  • 自等待检查:禁止协程等待自身。
  • 目标存在性:若目标不存在,直接返回(不阻塞当前协程)。
  • 当前协程状态:设置为 Held防止被 Update 推进。
  • 等待登记:将当前协程加入“被等待者”的等待集合。
  • 唤醒逻辑:目标协程完成后,遍历等待者集合,逐个恢复为 Running 并清理等待登记。
sequenceDiagram
participant Caller as "调用方"
participant Scheduler as "CoroutineScheduler"
participant Curr as "当前协程槽位"
participant Target as "目标协程槽位"
participant WaitSet as "等待集合"
Caller->>Scheduler : WaitForCoroutine(current, target)
Scheduler->>Scheduler : 检查是否等待自身
alt 等待自身
Scheduler-->>Caller : 抛出异常
else 非自身
Scheduler->>Scheduler : 检查目标是否存在
opt 目标存在
Scheduler->>Curr : 设置为 Held
Scheduler->>WaitSet : 将 current 加入 target 的等待集合
end
end
Note over Target,Scheduler : 目标协程完成后
Target->>Scheduler : Complete(slotIndex)
Scheduler->>WaitSet : 获取等待者集合
loop 对每个等待者
Scheduler->>Curr : 设置为 Running
end
Scheduler->>WaitSet : 清理等待集合

图表来源

章节来源

标签系统与批量管理

  • 标签注册Run 时若提供标签,加入标签集合并同步到元数据。
  • 批量终止KillByTag 遍历标签集合中的句柄,逐一调用 Kill。
  • 清空Clear 将所有集合清空并重置计数与索引。
flowchart TD
AddTag["AddTag(tag, handle)"] --> Lookup{"标签存在?"}
Lookup --> |否| NewSet["新建集合并加入 handle"]
Lookup --> |是| Append["追加 handle 到集合"]
NewSet --> MetaTag["元数据写入 Tag"]
Append --> MetaTag
KillByTag["KillByTag(tag)"] --> Exists{"标签存在?"}
Exists --> |否| ReturnZero["返回 0"]
Exists --> |是| Copy["复制句柄集合"]
Copy --> Loop["遍历句柄并 Kill"]
Loop --> Count["累计计数"]
Count --> ReturnCount["返回计数"]
Clear["Clear()"] --> Reset["清空集合/数组/计数/索引"]

图表来源

章节来源

等待指令族与使用建议

  • Delay基于剩余时间递减适合秒级延迟。
  • WaitOneFrame每帧完成一次适合简单帧等待。
  • WaitForFrames基于帧计数适合固定帧数等待。
  • WaitUntil/WaitWhile基于谓词函数适合条件等待。
  • WaitForCoroutine用于协程间依赖等待需配合调度器的等待登记与唤醒。

章节来源

依赖关系分析

  • 调度器依赖抽象接口 IYieldInstruction 与枚举 CoroutineState保证跨平台与可替换性。
  • 等待指令实现遵循统一接口,调度器通过 Update 驱动其状态变化。
  • 句柄与元数据形成强关联,槽位数组提供 O(1) 访问,元数据字典提供 O(1) 查询。
  • 标签集合与等待集合均为哈希结构,支持高效插入、删除与遍历。
graph LR
YI["IYieldInstruction"] --> D["Delay"]
YI --> WOF["WaitOneFrame"]
YI --> WFF["WaitForFrames"]
YI --> WU["WaitUntil"]
YI --> WW["WaitWhile"]
YI --> WFC["WaitForCoroutine"]
CS["CoroutineState"] --> S["CoroutineScheduler"]
YI --> S
S --> L["CoroutineSlot"]
S --> M["CoroutineMetadata"]
S --> H["CoroutineHandle"]

图表来源

章节来源

性能考量

  • 时间源驱动Update 先驱动时间源,确保等待指令的 Update 使用一致的 DeltaTime。
  • 线性遍历Update 对已分配槽位线性扫描,复杂度 O(N)N 为已分配槽位数。
  • 等待指令短路:若等待未完成,跳过 MoveNext避免无意义推进。
  • 预热机制Run 时预热一次,减少首帧推进成本。
  • 容量扩展:按倍增策略扩容,摊销写入成本,降低频繁扩容开销。
  • 异常处理:统一捕获并完成协程,避免异常传播影响调度器稳定性。
  • 标签与等待集合:使用 HashSet插入/删除/查找平均 O(1),适合高频操作。

章节来源

故障排查指南

  • 协程未推进:确认协程枚举器返回的等待指令是否正确,且 IsDone 在条件满足时为 true。
  • 协程卡住:检查等待指令 Update 是否被调用,以及剩余时间/帧数是否递减。
  • WaitForCoroutine 无效:确认目标协程句柄有效,且当前协程被设置为 Held。
  • 标签批量终止无效:确认标签名一致,且句柄仍在调度器中。
  • 异常导致协程提前结束:查看控制台错误输出,定位异常点并修复协程逻辑。
  • 槽位不足:观察活跃协程数量增长趋势,必要时增大 initialCapacity 或优化协程生命周期。

章节来源

结论

CoroutineScheduler 通过“槽位+元数据”的紧凑结构实现了高性能的协程调度,结合统一的等待指令接口与完善的生命周期管理,既保证了易用性也兼顾了性能与可维护性。配合标签系统与批量管理能力,能够满足复杂场景下的协程编排需求。

附录

使用示例与最佳实践

  • 基础使用:通过 Run 启动协程,传入等待指令实现延迟、帧等待或条件等待。
  • 条件等待:使用 WaitUntil/WaitWhile 根据业务状态动态决定协程推进时机。
  • 协程间依赖:使用 WaitForCoroutine 建立依赖关系,目标完成后自动唤醒等待者。
  • 标签管理:为协程打标签,便于批量终止与统计。
  • 性能优化:合理设置 initialCapacity避免频繁扩容尽量使用轻量等待指令及时 Kill 长生命周期协程。

章节来源