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

19 KiB
Raw Blame History

协程句柄与元数据

**本文引用的文件** - [CoroutineHandle.cs](file://GFramework.Core/coroutine/CoroutineHandle.cs) - [CoroutineMetadata.cs](file://GFramework.Core/coroutine/CoroutineMetadata.cs) - [CoroutineSlot.cs](file://GFramework.Core/coroutine/CoroutineSlot.cs) - [CoroutineScheduler.cs](file://GFramework.Core/coroutine/CoroutineScheduler.cs) - [CoroutineState.cs](file://GFramework.Core.Abstractions/coroutine/CoroutineState.cs) - [IYieldInstruction.cs](file://GFramework.Core.Abstractions/coroutine/IYieldInstruction.cs) - [CoroutineHelper.cs](file://GFramework.Core/coroutine/CoroutineHelper.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) - [WaitForCoroutine.cs](file://GFramework.Core/coroutine/WaitForCoroutine.cs) - [CoroutineHandleTests.cs](file://GFramework.Core.Tests/coroutine/CoroutineHandleTests.cs) - [CoroutineSchedulerTests.cs](file://GFramework.Core.Tests/coroutine/CoroutineSchedulerTests.cs)

目录

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

简介

本文件围绕协程句柄与元数据管理系统进行深入技术解析,涵盖以下主题:

  • 协程句柄的设计理念与唯一标识机制实例ID、句柄有效性验证
  • 协程元数据的数据结构与状态跟踪(槽位索引、协程状态、标签信息)
  • 协程槽位的内存结构与性能优化(枚举器存储、等待状态管理)
  • 协程状态枚举的转换与条件判断
  • 协程槽位的内存池化策略与容量扩展机制
  • 协程标识符的生成算法与冲突避免
  • 状态同步机制与并发安全性
  • 高并发场景下的性能表现与优化建议

项目结构

该系统位于 GFramework.Core 的 coroutine 命名空间下,并通过抽象层 IYieldInstruction 和 CoroutineState 提供跨平台与可扩展的协程基础能力。

graph TB
subgraph "协程抽象层"
A["CoroutineState.cs"]
B["IYieldInstruction.cs"]
end
subgraph "协程核心实现"
C["CoroutineHandle.cs"]
D["CoroutineMetadata.cs"]
E["CoroutineSlot.cs"]
F["CoroutineScheduler.cs"]
G["CoroutineHelper.cs"]
end
subgraph "等待指令实现"
H["Delay.cs"]
I["WaitOneFrame.cs"]
J["WaitForFrames.cs"]
K["WaitUntil.cs"]
L["WaitWhile.cs"]
M["WaitForCoroutine.cs"]
end
F --> C
F --> D
F --> E
F --> A
F --> B
G --> H
G --> I
G --> J
G --> K
G --> L
G --> M

图表来源

章节来源

核心组件

  • 协程句柄CoroutineHandle轻量级结构体负责唯一标识协程实例支持有效性判断与相等性比较。
  • 元数据CoroutineMetadata记录协程在调度器中的槽位索引、当前状态与标签信息并提供活跃状态判断。
  • 槽位CoroutineSlot承载单个协程的枚举器、当前状态与等待指令是调度器内存池的基本单元。
  • 调度器CoroutineScheduler管理协程生命周期、状态更新、暂停/恢复/终止、等待机制、标签管理与容量扩展。
  • 状态枚举CoroutineState定义协程的执行状态集合。
  • 等待指令IYieldInstruction 及其实现):封装等待条件与时间控制,驱动协程暂停与恢复。

章节来源

架构总览

调度器采用“槽位数组 + 字典映射”的内存池化设计,通过句柄与元数据建立索引,实现 O(1) 级别的状态查询与更新;等待机制通过字典维护“被等待者 → 等待者集合”,在被等待者完成后批量唤醒。

classDiagram
class CoroutineHandle {
+byte Key
+bool IsValid
+Equals(other) bool
+GetHashCode() int
}
class CoroutineMetadata {
+int SlotIndex
+CoroutineState State
+string Tag
+bool IsActive
}
class CoroutineSlot {
+IEnumerator~IYieldInstruction~ Enumerator
+CoroutineState State
+IYieldInstruction Waiting
}
class CoroutineScheduler {
-Dictionary~CoroutineHandle,CoroutineMetadata~ _metadata
-Dictionary~string,HashSet~CoroutineHandle~~ _tagged
-Dictionary~CoroutineHandle,HashSet~CoroutineHandle~~ _waiting
-CoroutineSlot?[] _slots
+Run(coroutine, tag) CoroutineHandle
+Update() void
+Pause(handle) bool
+Resume(handle) bool
+Kill(handle) bool
+WaitForCoroutine(current, target) void
+KillByTag(tag) int
+Clear() int
}
class CoroutineState {
<<enum>>
+Running
+Paused
+Held
+Completed
+Cancelled
}
class IYieldInstruction {
<<interface>>
+bool IsDone
+void Update(deltaTime)
}
CoroutineScheduler --> CoroutineHandle : "创建/管理"
CoroutineScheduler --> CoroutineMetadata : "维护"
CoroutineScheduler --> CoroutineSlot : "内存池"
CoroutineScheduler --> CoroutineState : "使用"
CoroutineScheduler --> IYieldInstruction : "驱动等待"

图表来源

详细组件分析

协程句柄CoroutineHandle

  • 设计理念
    • 使用只读结构体,确保不可变性与高性能。
    • 通过“实例ID + 递增步长”生成唯一内部IDKey 为低4位用于区分同一实例内的不同槽位。
  • 唯一标识与冲突避免
    • NextIndex[instanceId] 按 ReservedSpace+1 步长递增保证同一实例内句柄Key不冲突。
    • Key=0 视为无效句柄default(CoroutineHandle) 无效。
  • 有效性验证
    • IsValid 基于 Key 是否为 0。
    • 相等性比较基于内部ID操作符重载与 GetHasCode 保持一致性。
flowchart TD
Start(["创建句柄"]) --> CheckId["校验实例ID是否超过预留空间"]
CheckId --> AdjustId["必要时对实例ID做偏移调整"]
AdjustId --> CalcId["计算内部ID = NextIndex[instanceId] + instanceId"]
CalcId --> IncNext["NextIndex[instanceId] += ReservedSpace + 1"]
IncNext --> SetKey["Key = 内部ID & ReservedSpace"]
SetKey --> Valid{"Key == 0 ?"}
Valid --> |是| MarkInvalid["标记为无效"]
Valid --> |否| MarkValid["标记为有效"]
MarkInvalid --> End(["返回句柄"])
MarkValid --> End

图表来源

章节来源

协程元数据CoroutineMetadata

  • 数据结构
    • SlotIndex协程在调度器槽位数组中的索引。
    • State当前执行状态运行/暂停/持有/完成/取消)。
    • Tag协程标签便于按标签管理与查找。
    • IsActive活跃状态判断运行/暂停/持有)。
  • 作用
    • 作为调度器字典的值,提供从句柄到槽位与状态的快速映射。

章节来源

协程槽位CoroutineSlot

  • 数据结构
    • Enumerator协程枚举器承载协程执行逻辑。
    • State当前状态。
    • Waiting当前等待指令控制暂停与恢复。
  • 性能优化
    • 使用非空槽位数组避免频繁分配与GC。
    • 通过预热Prewarm在首次运行时推进一步减少首帧延迟。

章节来源

协程调度器CoroutineScheduler

  • 生命周期管理
    • Run创建句柄、分配槽位、初始化元数据、预热、注册标签。
    • Update遍历槽位处理等待指令、推进枚举器、异常捕获与清理。
    • Pause/Resume/Kill修改槽位与元数据状态维护活跃计数。
  • 等待机制
    • WaitForCoroutine将当前协程置为 Held登记“被等待者 → 等待者集合”,被等待者完成后批量唤醒。
  • 标签管理
    • AddTag/RemoveTag按标签维护句柄集合支持 KillByTag。
  • 容量扩展
    • Expand按2倍扩容槽位数组保证摊销成本合理。
  • 并发与同步
    • Update 中对每个槽位独立处理,避免跨协程竞争。
    • 元数据与槽位通过句柄与索引关联,读写路径清晰。
sequenceDiagram
participant S as "调度器"
participant T as "时间源"
participant SL as "槽位"
participant Y as "等待指令"
S->>T : Update()
T-->>S : DeltaTime
loop 遍历槽位
S->>SL : 读取状态
alt 状态为运行
S->>SL : 若存在等待指令
S->>Y : Update(DeltaTime)
alt 未完成
S-->>S : 跳过本轮
else 已完成
S->>SL : 清空Waiting
end
end
S->>SL : Enumerator.MoveNext()
alt 成功
S->>SL : 设置Waiting = Current
else 失败
S->>S : Complete(SlotIndex)
end
else 非运行
S-->>S : 跳过
end
end

图表来源

章节来源

协程状态枚举CoroutineState

  • 状态定义
    • Running运行中
    • Paused已暂停
    • Held被锁定或等待其他协程
    • Completed已完成
    • Cancelled已取消
  • 条件判断
    • IsActive 基于 Running/Paused/Held 三态。
    • 等待机制中WaitForCoroutine 将当前协程置为 Held直至被等待者完成。

章节来源

等待指令体系IYieldInstruction 及实现)

  • 接口契约
    • IsDone是否完成
    • Update(deltaTime):每帧更新状态
  • 常见实现
    • Delay基于剩余时间计数
    • WaitOneFrame单帧等待
    • WaitForFrames基于剩余帧数
    • WaitUntil/WaitWhile基于谓词函数
    • WaitForCoroutine内部完成标记
classDiagram
class IYieldInstruction {
<<interface>>
+bool IsDone
+void Update(deltaTime)
}
class Delay {
-double _remaining
+Update(deltaTime) void
+IsDone bool
}
class WaitOneFrame {
-bool _done
+Update(deltaTime) void
+IsDone bool
}
class WaitForFrames {
-int _remaining
+Update(deltaTime) void
+IsDone bool
}
class WaitUntil {
-Func~bool~ _predicate
+Update(deltaTime) void
+IsDone bool
}
class WaitWhile {
-Func~bool~ _predicate
+Update(deltaTime) void
+IsDone bool
}
class WaitForCoroutine {
-bool _done
+Update(deltaTime) void
+IsDone bool
+Complete() void
}
Delay ..|> IYieldInstruction
WaitOneFrame ..|> IYieldInstruction
WaitForFrames ..|> IYieldInstruction
WaitUntil ..|> IYieldInstruction
WaitWhile ..|> IYieldInstruction
WaitForCoroutine ..|> IYieldInstruction

图表来源

章节来源

依赖关系分析

  • 抽象依赖
    • CoroutineScheduler 依赖 IYieldInstruction 与 CoroutineState确保调度逻辑与等待指令解耦。
  • 内部耦合
    • 调度器通过句柄与元数据建立索引,再定位槽位,形成稳定的读写路径。
    • 元数据与槽位一一对应,通过 SlotIndex 关联,避免额外映射开销。
  • 外部依赖
    • 时间源 ITimeSource 由外部注入,便于测试与平台适配。
graph LR
IY["IYieldInstruction"] --> SCH["CoroutineScheduler"]
CS["CoroutineState"] --> SCH
SCH --> HND["CoroutineHandle"]
SCH --> META["CoroutineMetadata"]
SCH --> SLOT["CoroutineSlot"]

图表来源

章节来源

性能考量

  • 内存池化与容量扩展
    • 槽位数组按2倍扩容摊销插入成本初始容量可配置以平衡启动内存占用。
  • 状态更新复杂度
    • Update 对每个槽位执行常数次操作,整体 O(n)n 为已分配槽位数。
  • 等待机制
    • 等待字典使用 HashSet 存储等待者,唤醒时批量处理,避免逐个检查。
  • 哈希与相等性
    • 句柄基于内部ID的哈希与相等性适合字典键使用冲突概率低。
  • 并发安全
    • Update 为单线程推进,无锁设计;若需多线程,应在外部加锁或使用线程安全队列。

章节来源

故障排查指南

  • 句柄无效
    • 现象IsValid 为 false 或 Key 为 0。
    • 排查:确认是否使用了 default 句柄或实例ID超过预留空间导致偏移。
  • 协程未更新
    • 现象:暂停后 Update 不推进。
    • 排查:确认 Pause/Resume 流程与状态切换。
  • 等待死锁
    • 现象WaitForCoroutine 导致协程长期 Held。
    • 排查:确认被等待者最终完成并触发唤醒。
  • 异常处理
    • 现象:协程抛出异常后活跃计数未减少。
    • 排查:确认 OnError 路径正确清理并输出日志。
  • 标签管理
    • 现象KillByTag 无法终止目标协程。
    • 排查:确认标签注册与注销流程一致。

章节来源

结论

该协程系统通过“句柄 + 元数据 + 槽位”的组合,实现了高效、可扩展的协程调度与管理。其关键优势包括:

  • 唯一标识与冲突避免基于实例ID与步长的句柄生成策略。
  • 状态跟踪与等待机制:通过元数据与等待字典实现清晰的状态流转。
  • 内存池化与容量扩展数组式槽位与2倍扩容兼顾性能与弹性。
  • 解耦与可测试性:抽象接口与注入式时间源,便于单元测试与平台适配。

附录

  • 单元测试参考
    • 句柄有效性、相等性、哈希一致性与多实例独立性。
    • 调度器运行、暂停/恢复、终止、等待、标签管理与容量扩展。
  • 使用建议
    • 在高并发场景下,建议在外部统一推进 Update避免多线程竞争。
    • 合理设置 initialCapacity减少扩容次数。
    • 使用标签进行分组管理,配合 KillByTag 快速清理。

章节来源