Skip to content

Docs/coroutine system refactor#99

Merged
GeWuYou merged 3 commits into
mainfrom
docs/coroutine-system-refactor
Mar 12, 2026
Merged

Docs/coroutine system refactor#99
GeWuYou merged 3 commits into
mainfrom
docs/coroutine-system-refactor

Conversation

@GeWuYou

@GeWuYou GeWuYou commented Mar 12, 2026

Copy link
Copy Markdown
Owner

Summary by Sourcery

更新和扩展协程系统在核心库和 Godot 集成部分的文档,使其与重构后的基于 IEnumerator/IYieldInstruction 的调度器以及新的扩展 API 保持一致。

文档内容:

  • 修订核心协程文档,重点强调 CoroutineScheduler/CoroutineHandle/IYieldInstruction 模型、分组等待指令,以及与任务(tasks)、事件(events)、命令(commands)、查询(queries)和 Mediator 的集成。
  • 重构 Godot 协程文档,描述分层设计(核心 vs Godot 集成)、基于分段的调度、通过 CancelWith 进行的节点生命周期绑定、常用等待指令以及基于 IContextAware 的命令/查询辅助工具。
Original summary in English

Summary by Sourcery

Update and expand coroutine system documentation for both core and Godot integrations, aligning it with the refactored IEnumerator/IYieldInstruction-based scheduler and new extension APIs.

Documentation:

  • Revise core coroutine documentation to emphasize the CoroutineScheduler/CoroutineHandle/IYieldInstruction model, grouped wait instructions, and integration with tasks, events, commands, queries, and Mediator.
  • Restructure Godot coroutine documentation to describe the layered design (core vs Godot integration), segment-based scheduling, node lifecycle binding via CancelWith, common wait instructions, and IContextAware-based command/query helpers.

GeWuYou added 2 commits March 12, 2026 12:41
- 重构协程系统架构说明,明确核心组件和入口点
- 更新协程启动方式和基本用法示例代码
- 添加 Segment 分段调度机制详细说明
- 补充节点生命周期绑定和延迟调用功能介绍
- 完善常用等待指令和协程控制方法文档
- 优化事件总线集成和上下文感知集成说明
- 重新描述协程系统功能,强调基于 IEnumerator<IYieldInstruction> 的调度能力
- 更新核心概念介绍,明确协程系统的组成部分和架构设计
- 修改 CoroutineScheduler 使用示例,添加统计信息启用说明
- 完善 CoroutineHandle 的控制方法说明,包括暂停、恢复和终止操作
- 优化协程状态控制示例代码,展示标签和分组管理功能
- 重构等待指令说明,按时间帧、条件等待、Task桥接等方式分类
- 更新事件等待相关示例,改进超时处理和多事件等待功能
- 完善协程组合功能说明,包括子协程等待和多句柄等待
- 优化扩展方法介绍,按组合扩展、协程生成扩展、Task扩展等分类
- 更新命令、查询和Mediator扩展使用说明
- 修订异常处理机制说明,明确调度器异常处理方式
- 更新常见问题解答,澄清协程执行时机和线程模型概念
- 精简相关文档链接,移除冗余的系统集成说明
@sourcery-ai

sourcery-ai Bot commented Mar 12, 2026

Copy link
Copy Markdown

审阅者指南

重构并大幅扩展了 Core 和 Godot 集成部分的协程文档,使术语与新的基于 IEnumerator<IYieldInstruction> 的系统保持一致,补充了对 CoroutineScheduler / CoroutineHandle / 各种 Instruction / 扩展方法的说明,涵盖基于 Segment 的调度、节点生命周期绑定,以及与命令 / 查询 / 事件 / Mediator 的集成,同时清理了过时的模式和最佳实践章节。

在 Godot 中使用 Segment 和 CancelWith 节点绑定运行协程的时序图

sequenceDiagram
    participant MyNode
    participant Coroutine as DemoCoroutine
    participant Timing
    participant Scheduler as CoroutineScheduler
    participant Node as GodotNode

    MyNode->>MyNode: _Ready()
    MyNode->>Coroutine: Demo()
    activate Coroutine
    Coroutine-->>MyNode: IEnumerator_IYieldInstruction_

    MyNode->>Coroutine: CancelWith(Node)
    Coroutine-->>MyNode: wrapped_IEnumerator

    MyNode->>Timing: RunCoroutine(wrapped_IEnumerator, Segment.Process, tag)
    activate Timing
    Timing->>Scheduler: Run(wrapped_IEnumerator, tag, group)
    activate Scheduler
    Scheduler-->>Timing: CoroutineHandle
    Timing-->>MyNode: CoroutineHandle
    deactivate Timing

    loop each_frame_in_Process
        MyNode->>Timing: internal_Process_callback
        Timing->>Scheduler: Update()
        Scheduler->>Coroutine: MoveNext(deltaTime)
        alt coroutine_yields_Delay
            Coroutine-->>Scheduler: Delay_instruction
            Scheduler-->>Scheduler: schedule_wait_seconds
        else coroutine_completes
            Coroutine-->>Scheduler: completed
            Scheduler-->>Scheduler: release_handle
        end
    end

    par Node_exits_scene_tree
        Node-->>Coroutine: cancellation_signal
        Coroutine-->>Scheduler: stop_iteration
        Scheduler-->>Scheduler: Kill(CoroutineHandle)
    end

    deactivate Scheduler
    deactivate Coroutine
Loading

使用 IContextAware 和 WaitForEventWithTimeout 的命令 + 事件协程时序图

sequenceDiagram
    participant Controller as GodotNode_Controller
    participant Context as IContextAware
    participant Scheduler as CoroutineScheduler
    participant EventBus as IEventBus
    participant Command as LoadSceneCommand
    participant WaitInstr as WaitForEventWithTimeout_SceneLoadedEvent_
    participant Coroutine as CommandCoroutine

    Controller->>Context: SendCommandAndWaitEventCoroutine(Command, handler, timeout)
    activate Context
    Context-->>Coroutine: IEnumerator_IYieldInstruction_
    deactivate Context

    Controller->>Scheduler: Run(Coroutine, tag, group)
    activate Scheduler
    Scheduler-->>Controller: CoroutineHandle

    note over Coroutine,Scheduler: 协程体开始执行
    Coroutine->>Context: SendCommand(Command)
    Context->>Command: Execute()
    Command-->>Context: Task_completion

    Coroutine->>EventBus: create_WaitForEvent_SceneLoadedEvent_
    activate WaitInstr
    Coroutine->>Scheduler: yield WaitForEventWithTimeout_SceneLoadedEvent_(WaitForEvent, timeoutSeconds)

    loop scheduler_updates
        Scheduler->>WaitInstr: poll_status(deltaTime)
        alt event_published_before_timeout
            EventBus-->>WaitInstr: SceneLoadedEvent
            WaitInstr-->>Coroutine: IsTimeout=false, EventData
            Coroutine-->>Scheduler: resume_execution
            Coroutine->>Controller: handler(EventData)
            Coroutine-->>Scheduler: complete
            Scheduler-->>Scheduler: release_handle
            note over Scheduler: break
        else timeout_elapsed
            WaitInstr-->>Coroutine: IsTimeout=true
            Coroutine-->>Scheduler: resume_execution
            Coroutine->>Controller: handler_timeout_branch
            Coroutine-->>Scheduler: complete
            Scheduler-->>Scheduler: release_handle
            note over Scheduler: break
        end
    end

    deactivate WaitInstr
    deactivate Scheduler
Loading

更新后的核心协程系统类图

classDiagram
    direction LR

    class CoroutineScheduler {
        +CoroutineScheduler(ITimeSource timeSource, bool enableStatistics)
        +CoroutineHandle Run(IEnumerator_IYieldInstruction_ routine, string tag, string group)
        +bool IsCoroutineAlive(CoroutineHandle handle)
        +void Pause(CoroutineHandle handle)
        +void Resume(CoroutineHandle handle)
        +void Kill(CoroutineHandle handle)
        +void KillByTag(string tag)
        +void PauseGroup(string group)
        +void ResumeGroup(string group)
        +void KillGroup(string group)
        +bool Clear()
        +void Update()
        +event OnCoroutineException
    }

    class CoroutineHandle {
        +int Id
        +string Tag
        +string Group
    }

    class IYieldInstruction {
        <<interface>>
        +bool MoveNext(double deltaTime)
    }

    class Delay {
        +double Seconds
    }

    class WaitForSecondsRealtime {
        +double Seconds
    }

    class WaitOneFrame {
    }

    class WaitForNextFrame {
    }

    class WaitForFrames {
        +int FrameCount
    }

    class WaitForEndOfFrame {
    }

    class WaitUntil {
        +Func_bool_ Predicate
    }

    class WaitWhile {
        +Func_bool_ Predicate
    }

    class WaitForEvent_TEvent_ {
        +TEvent EventData
        +bool IsCompleted
        +Dispose()
    }

    class WaitForEventWithTimeout_TEvent_ {
        +TEvent EventData
        +bool IsTimeout
    }

    class WaitForMultipleEvents_TFirst_TSecond_ {
        +int TriggeredBy
        +TFirst FirstEventData
        +TSecond SecondEventData
    }

    class WaitForCoroutine {
        +IEnumerator_IYieldInstruction_ Routine
    }

    class WaitForAllCoroutines {
        +IReadOnlyList_CoroutineHandle_ Handles
    }

    class CoroutineHelper {
        <<static>>
        +IYieldInstruction WaitForSeconds(double seconds)
        +IYieldInstruction WaitForOneFrame()
        +IYieldInstruction WaitForFrames(int frames)
        +IYieldInstruction WaitUntil(Func_bool_ predicate)
        +IYieldInstruction WaitWhile(Func_bool_ predicate)
        +IEnumerator_IYieldInstruction_ DelayedCall(double seconds, Action action)
        +IEnumerator_IYieldInstruction_ RepeatCall(double interval, int count, Action action)
        +IEnumerator_IYieldInstruction_ RepeatCallForever(double interval, Action action, CancellationToken token)
        +IEnumerator_IYieldInstruction_ WaitForProgress(double duration, Action_double_ onProgress)
    }

    class CoroutineExtensions {
        <<static>>
        +IEnumerator_IYieldInstruction_ ExecuteAfter(double seconds, Action action)
        +IEnumerator_IYieldInstruction_ RepeatEvery(double interval, Action action, int count)
        +IEnumerator_IYieldInstruction_ WaitForSecondsWithProgress(double seconds, Action_double_ onProgress)
        +IEnumerator_IYieldInstruction_ Sequence(IEnumerator_IYieldInstruction_ first, IEnumerator_IYieldInstruction_ second, IEnumerator_IYieldInstruction_ third)
    }

    class CoroutineComposeExtensions {
        <<static>>
        +IEnumerator_IYieldInstruction_ Then(IEnumerator_IYieldInstruction_ first, Action continuation)
        +IEnumerator_IYieldInstruction_ Then(IEnumerator_IYieldInstruction_ first, IEnumerator_IYieldInstruction_ next)
    }

    class TaskCoroutineExtensions {
        <<static>>
        +IYieldInstruction AsCoroutineInstruction(Task task)
        +IYieldInstruction AsCoroutineInstruction_T_(Task_T_ task)
        +IEnumerator_IYieldInstruction_ ToCoroutineEnumerator(Task task)
        +IEnumerator_IYieldInstruction_ ToCoroutineEnumerator_T_(Task_T_ task)
        +CoroutineHandle StartTaskAsCoroutine(CoroutineScheduler scheduler, Task task)
        +CoroutineHandle StartTaskAsCoroutine_T_(CoroutineScheduler scheduler, Task_T_ task)
    }

    class IEventBus {
        <<interface>>
    }

    class IContextAware {
        <<interface>>
    }

    class Mediator_IMediator_ {
    }

    CoroutineScheduler --> CoroutineHandle : creates
    CoroutineScheduler ..> IYieldInstruction : schedules
    CoroutineScheduler ..> IEventBus : used_by_instructions

    IYieldInstruction <|.. Delay
    IYieldInstruction <|.. WaitForSecondsRealtime
    IYieldInstruction <|.. WaitOneFrame
    IYieldInstruction <|.. WaitForNextFrame
    IYieldInstruction <|.. WaitForFrames
    IYieldInstruction <|.. WaitForEndOfFrame
    IYieldInstruction <|.. WaitUntil
    IYieldInstruction <|.. WaitWhile
    IYieldInstruction <|.. WaitForEvent_TEvent_
    IYieldInstruction <|.. WaitForEventWithTimeout_TEvent_
    IYieldInstruction <|.. WaitForMultipleEvents_TFirst_TSecond_
    IYieldInstruction <|.. WaitForCoroutine
    IYieldInstruction <|.. WaitForAllCoroutines

    WaitForEvent_TEvent_ --> IEventBus : subscribes
    WaitForEventWithTimeout_TEvent_ --> WaitForEvent_TEvent_ : wraps
    WaitForMultipleEvents_TFirst_TSecond_ --> IEventBus : subscribes

    CoroutineHelper ..> IYieldInstruction : constructs
    CoroutineHelper ..> IEnumerator_IYieldInstruction_ : generators

    CoroutineExtensions ..> IEnumerator_IYieldInstruction_ : composition
    CoroutineComposeExtensions ..> IEnumerator_IYieldInstruction_ : fluent_sequence

    TaskCoroutineExtensions ..> IYieldInstruction : wraps_Task
    TaskCoroutineExtensions ..> IEnumerator_IYieldInstruction_ : converts_Task
    TaskCoroutineExtensions ..> CoroutineScheduler : starts_Task_coroutines

    IContextAware ..> CoroutineScheduler : has_access_to
    IContextAware ..> IEventBus : has_access_to
    IContextAware ..> Mediator_IMediator_ : optional
Loading

文件级变更

变更 细节 文件
围绕 CoroutineScheduler、CoroutineHandle、IYieldInstruction、辅助方法 / 扩展 API 以及集成点重写核心协程文档。
  • 用对基于 IEnumerator<IYieldInstruction> 的调度模型及 CoroutineScheduler 角色的具体描述,替换原有偏营销风格的高层概览。
  • 新增明确的章节,讲解如何通过 ITimeSource 构造 CoroutineScheduler、启用统计信息,以及基于 handle 的控制(暂停、恢复、杀死、打标签、分组、清理)。
  • 围绕 IYieldInstruction 接口重新阐述“yield 指令”的概念,并展示规范的使用模式,包括基于时间、帧数、条件、Task 和事件的等待。
  • 文档化 CoroutineHelper 辅助方法(WaitForSecondsWaitUntilDelayedCallRepeatCallWaitForProgress 等),并展示其既可作为 yield 指令使用,又可作为可直接运行的协程。
  • 新增章节介绍 TaskCoroutineExtensions、命令 / 查询 / Mediator 协程扩展,以及事件相关的指令,例如 WaitForEventWaitForEventWithTimeoutWaitForMultipleEventsWaitForCoroutineWaitForAllCoroutines
  • 新增协程组合与生成扩展章节(Then 链式调用、SequenceParallelCoroutines),并明确说明通过 OnCoroutineExceptionWaitForTask 进行异常处理的方式。
  • 移除或精简旧的最佳实践和 FAQ 内容,用与新 API 语义对齐的 FAQ 取而代之(如 Delay vs WaitForSeconds、线程、执行时机等)。
docs/zh-CN/core/coroutine.md
重构 Godot 协程文档,使其与核心协程系统和 Godot 集成层 API 对齐。
  • 用“两层结构”的描述(核心协程系统 + Godot 集成层)替换旧的 Godot 专用协程叙述(StartCoroutineWaitSignal、通用模式)。
  • 文档化 RunCoroutineTiming 静态辅助方法(RunGameCoroutineRunUiCoroutineCallDelayedPrewarm),以及它们如何映射到不同的 Segment 值(ProcessProcessIgnorePausePhysicsProcessDeferredProcess)。
  • 引入 CancelWith(Node...) 生命周期绑定语义,并解释节点销毁如何取消关联的协程。
  • 使 Godot 文档与基于 IYieldInstruction 的等待方式保持一致(DelayWaitForSecondsRealtimeWaitOneFrameWaitForEndOfFrame 等),以及通过核心扩展进行 Task / 事件总线等待。
  • 补充关于协程 handle 以及通过 Timing 进行全局控制(按 handle / tag / all 暂停 / 恢复 / 杀死)的说明,并阐述如何在 Godot 场景中使用 WaitForEvent 等待事件。
  • 用更精简的 IContextAware 命令 / 查询 / 发布协程辅助方法集成章节,以及简化后的相关文档列表,取代此前关于上下文感知 / 源生成器 / 日志记录 / UI 绑定的最佳实践。
docs/zh-CN/godot/coroutine.md

提示与命令

与 Sourcery 交互

  • 触发新的代码审查: 在 Pull Request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 在某条审查评论下回复,要求 Sourcery 从该评论创建 issue。你也可以直接回复该评论 @sourcery-ai issue 来生成 issue。
  • 生成 Pull Request 标题: 在 Pull Request 标题中任意位置写入 @sourcery-ai 即可随时生成标题。你也可以在 Pull Request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 Pull Request 摘要: 在 Pull Request 描述正文中任意位置写入 @sourcery-ai summary,即可在该位置生成 PR 摘要。你也可以在 Pull Request 中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审阅者指南: 在 Pull Request 中评论 @sourcery-ai guide,即可随时(重新)生成审阅者指南。
  • 一次性解决所有 Sourcery 评论: 在 Pull Request 中评论 @sourcery-ai resolve,即可将所有 Sourcery 评论标记为已解决。如果你已经处理完所有评论且不想再看到它们,这会非常有用。
  • 一次性忽略所有 Sourcery 审查: 在 Pull Request 中评论 @sourcery-ai dismiss,即可忽略所有已存在的 Sourcery 审查。如果你希望从一次全新的审查开始,这会特别有用——别忘了随后再评论 @sourcery-ai review 触发新的审查!

自定义你的使用体验

访问你的 控制面板 以:

  • 启用或禁用审查功能,例如 Sourcery 自动生成的 Pull Request 摘要、审阅者指南等。
  • 更改审查语言。
  • 添加、移除或编辑自定义审查指令。
  • 调整其它审查相关设置。

获取帮助

Original review guide in English

Reviewer's Guide

Refactors and significantly expands the coroutine documentation for both the Core and Godot integrations, aligning terminology with the new IEnumerator-based system, documenting CoroutineScheduler/CoroutineHandle/Instructions/Extensions, segment-based scheduling, node lifecycle binding, and command/query/event/Mediator integration, while pruning outdated patterns and best-practice sections.

Sequence diagram for running a Godot coroutine with Segment and CancelWith node binding

sequenceDiagram
    participant MyNode
    participant Coroutine as DemoCoroutine
    participant Timing
    participant Scheduler as CoroutineScheduler
    participant Node as GodotNode

    MyNode->>MyNode: _Ready()
    MyNode->>Coroutine: Demo()
    activate Coroutine
    Coroutine-->>MyNode: IEnumerator_IYieldInstruction_

    MyNode->>Coroutine: CancelWith(Node)
    Coroutine-->>MyNode: wrapped_IEnumerator

    MyNode->>Timing: RunCoroutine(wrapped_IEnumerator, Segment.Process, tag)
    activate Timing
    Timing->>Scheduler: Run(wrapped_IEnumerator, tag, group)
    activate Scheduler
    Scheduler-->>Timing: CoroutineHandle
    Timing-->>MyNode: CoroutineHandle
    deactivate Timing

    loop each_frame_in_Process
        MyNode->>Timing: internal_Process_callback
        Timing->>Scheduler: Update()
        Scheduler->>Coroutine: MoveNext(deltaTime)
        alt coroutine_yields_Delay
            Coroutine-->>Scheduler: Delay_instruction
            Scheduler-->>Scheduler: schedule_wait_seconds
        else coroutine_completes
            Coroutine-->>Scheduler: completed
            Scheduler-->>Scheduler: release_handle
        end
    end

    par Node_exits_scene_tree
        Node-->>Coroutine: cancellation_signal
        Coroutine-->>Scheduler: stop_iteration
        Scheduler-->>Scheduler: Kill(CoroutineHandle)
    end

    deactivate Scheduler
    deactivate Coroutine
Loading

Sequence diagram for command and event-based coroutine using IContextAware and WaitForEventWithTimeout

sequenceDiagram
    participant Controller as GodotNode_Controller
    participant Context as IContextAware
    participant Scheduler as CoroutineScheduler
    participant EventBus as IEventBus
    participant Command as LoadSceneCommand
    participant WaitInstr as WaitForEventWithTimeout_SceneLoadedEvent_
    participant Coroutine as CommandCoroutine

    Controller->>Context: SendCommandAndWaitEventCoroutine(Command, handler, timeout)
    activate Context
    Context-->>Coroutine: IEnumerator_IYieldInstruction_
    deactivate Context

    Controller->>Scheduler: Run(Coroutine, tag, group)
    activate Scheduler
    Scheduler-->>Controller: CoroutineHandle

    note over Coroutine,Scheduler: Coroutine body starts
    Coroutine->>Context: SendCommand(Command)
    Context->>Command: Execute()
    Command-->>Context: Task_completion

    Coroutine->>EventBus: create_WaitForEvent_SceneLoadedEvent_
    activate WaitInstr
    Coroutine->>Scheduler: yield WaitForEventWithTimeout_SceneLoadedEvent_(WaitForEvent, timeoutSeconds)

    loop scheduler_updates
        Scheduler->>WaitInstr: poll_status(deltaTime)
        alt event_published_before_timeout
            EventBus-->>WaitInstr: SceneLoadedEvent
            WaitInstr-->>Coroutine: IsTimeout=false, EventData
            Coroutine-->>Scheduler: resume_execution
            Coroutine->>Controller: handler(EventData)
            Coroutine-->>Scheduler: complete
            Scheduler-->>Scheduler: release_handle
            note over Scheduler: break
        else timeout_elapsed
            WaitInstr-->>Coroutine: IsTimeout=true
            Coroutine-->>Scheduler: resume_execution
            Coroutine->>Controller: handler_timeout_branch
            Coroutine-->>Scheduler: complete
            Scheduler-->>Scheduler: release_handle
            note over Scheduler: break
        end
    end

    deactivate WaitInstr
    deactivate Scheduler
Loading

Class diagram for the updated core coroutine system

classDiagram
    direction LR

    class CoroutineScheduler {
        +CoroutineScheduler(ITimeSource timeSource, bool enableStatistics)
        +CoroutineHandle Run(IEnumerator_IYieldInstruction_ routine, string tag, string group)
        +bool IsCoroutineAlive(CoroutineHandle handle)
        +void Pause(CoroutineHandle handle)
        +void Resume(CoroutineHandle handle)
        +void Kill(CoroutineHandle handle)
        +void KillByTag(string tag)
        +void PauseGroup(string group)
        +void ResumeGroup(string group)
        +void KillGroup(string group)
        +bool Clear()
        +void Update()
        +event OnCoroutineException
    }

    class CoroutineHandle {
        +int Id
        +string Tag
        +string Group
    }

    class IYieldInstruction {
        <<interface>>
        +bool MoveNext(double deltaTime)
    }

    class Delay {
        +double Seconds
    }

    class WaitForSecondsRealtime {
        +double Seconds
    }

    class WaitOneFrame {
    }

    class WaitForNextFrame {
    }

    class WaitForFrames {
        +int FrameCount
    }

    class WaitForEndOfFrame {
    }

    class WaitUntil {
        +Func_bool_ Predicate
    }

    class WaitWhile {
        +Func_bool_ Predicate
    }

    class WaitForEvent_TEvent_ {
        +TEvent EventData
        +bool IsCompleted
        +Dispose()
    }

    class WaitForEventWithTimeout_TEvent_ {
        +TEvent EventData
        +bool IsTimeout
    }

    class WaitForMultipleEvents_TFirst_TSecond_ {
        +int TriggeredBy
        +TFirst FirstEventData
        +TSecond SecondEventData
    }

    class WaitForCoroutine {
        +IEnumerator_IYieldInstruction_ Routine
    }

    class WaitForAllCoroutines {
        +IReadOnlyList_CoroutineHandle_ Handles
    }

    class CoroutineHelper {
        <<static>>
        +IYieldInstruction WaitForSeconds(double seconds)
        +IYieldInstruction WaitForOneFrame()
        +IYieldInstruction WaitForFrames(int frames)
        +IYieldInstruction WaitUntil(Func_bool_ predicate)
        +IYieldInstruction WaitWhile(Func_bool_ predicate)
        +IEnumerator_IYieldInstruction_ DelayedCall(double seconds, Action action)
        +IEnumerator_IYieldInstruction_ RepeatCall(double interval, int count, Action action)
        +IEnumerator_IYieldInstruction_ RepeatCallForever(double interval, Action action, CancellationToken token)
        +IEnumerator_IYieldInstruction_ WaitForProgress(double duration, Action_double_ onProgress)
    }

    class CoroutineExtensions {
        <<static>>
        +IEnumerator_IYieldInstruction_ ExecuteAfter(double seconds, Action action)
        +IEnumerator_IYieldInstruction_ RepeatEvery(double interval, Action action, int count)
        +IEnumerator_IYieldInstruction_ WaitForSecondsWithProgress(double seconds, Action_double_ onProgress)
        +IEnumerator_IYieldInstruction_ Sequence(IEnumerator_IYieldInstruction_ first, IEnumerator_IYieldInstruction_ second, IEnumerator_IYieldInstruction_ third)
    }

    class CoroutineComposeExtensions {
        <<static>>
        +IEnumerator_IYieldInstruction_ Then(IEnumerator_IYieldInstruction_ first, Action continuation)
        +IEnumerator_IYieldInstruction_ Then(IEnumerator_IYieldInstruction_ first, IEnumerator_IYieldInstruction_ next)
    }

    class TaskCoroutineExtensions {
        <<static>>
        +IYieldInstruction AsCoroutineInstruction(Task task)
        +IYieldInstruction AsCoroutineInstruction_T_(Task_T_ task)
        +IEnumerator_IYieldInstruction_ ToCoroutineEnumerator(Task task)
        +IEnumerator_IYieldInstruction_ ToCoroutineEnumerator_T_(Task_T_ task)
        +CoroutineHandle StartTaskAsCoroutine(CoroutineScheduler scheduler, Task task)
        +CoroutineHandle StartTaskAsCoroutine_T_(CoroutineScheduler scheduler, Task_T_ task)
    }

    class IEventBus {
        <<interface>>
    }

    class IContextAware {
        <<interface>>
    }

    class Mediator_IMediator_ {
    }

    CoroutineScheduler --> CoroutineHandle : creates
    CoroutineScheduler ..> IYieldInstruction : schedules
    CoroutineScheduler ..> IEventBus : used_by_instructions

    IYieldInstruction <|.. Delay
    IYieldInstruction <|.. WaitForSecondsRealtime
    IYieldInstruction <|.. WaitOneFrame
    IYieldInstruction <|.. WaitForNextFrame
    IYieldInstruction <|.. WaitForFrames
    IYieldInstruction <|.. WaitForEndOfFrame
    IYieldInstruction <|.. WaitUntil
    IYieldInstruction <|.. WaitWhile
    IYieldInstruction <|.. WaitForEvent_TEvent_
    IYieldInstruction <|.. WaitForEventWithTimeout_TEvent_
    IYieldInstruction <|.. WaitForMultipleEvents_TFirst_TSecond_
    IYieldInstruction <|.. WaitForCoroutine
    IYieldInstruction <|.. WaitForAllCoroutines

    WaitForEvent_TEvent_ --> IEventBus : subscribes
    WaitForEventWithTimeout_TEvent_ --> WaitForEvent_TEvent_ : wraps
    WaitForMultipleEvents_TFirst_TSecond_ --> IEventBus : subscribes

    CoroutineHelper ..> IYieldInstruction : constructs
    CoroutineHelper ..> IEnumerator_IYieldInstruction_ : generators

    CoroutineExtensions ..> IEnumerator_IYieldInstruction_ : composition
    CoroutineComposeExtensions ..> IEnumerator_IYieldInstruction_ : fluent_sequence

    TaskCoroutineExtensions ..> IYieldInstruction : wraps_Task
    TaskCoroutineExtensions ..> IEnumerator_IYieldInstruction_ : converts_Task
    TaskCoroutineExtensions ..> CoroutineScheduler : starts_Task_coroutines

    IContextAware ..> CoroutineScheduler : has_access_to
    IContextAware ..> IEventBus : has_access_to
    IContextAware ..> Mediator_IMediator_ : optional
Loading

File-Level Changes

Change Details Files
Rewrite Core coroutine documentation around CoroutineScheduler, CoroutineHandle, IYieldInstruction, helper/extension APIs, and integration points.
  • Replace high-level marketing-style overview with a concrete description of the IEnumerator-based scheduling model and CoroutineScheduler role.
  • Introduce explicit sections for CoroutineScheduler construction with ITimeSource, enabling statistics, and handle-based control (pause, resume, kill, tagging, grouping, clear).
  • Reframe the concept of yield instructions around the IYieldInstruction interface and show canonical usage patterns, including time, frame, condition, Task, and event waits.
  • Document CoroutineHelper helpers (WaitForSeconds, WaitUntil, DelayedCall, RepeatCall, WaitForProgress, etc.) and show usage both as yield instructions and directly runnable coroutines.
  • Add sections detailing TaskCoroutineExtensions, command/query/Mediator coroutine extensions, and event-based instructions such as WaitForEvent, WaitForEventWithTimeout, WaitForMultipleEvents, WaitForCoroutine, and WaitForAllCoroutines.
  • Add new sections for coroutine composition and generation extensions (Then-chaining, Sequence, ParallelCoroutines) and clarify exception handling via OnCoroutineException and WaitForTask.
  • Remove or condense older best-practice and FAQ content, replacing it with updated FAQs aligned to the new API semantics (Delay vs WaitForSeconds, threading, execution timing).
docs/zh-CN/core/coroutine.md
Refactor Godot coroutine documentation to align with the Core coroutine system and Godot integration layer APIs.
  • Replace the old Godot-specific coroutine narrative (StartCoroutine, WaitSignal, generic patterns) with a two-layer description: core coroutine system and Godot integration layer.
  • Document RunCoroutine and Timing static helpers (RunGameCoroutine, RunUiCoroutine, CallDelayed, Prewarm) and how they map to different Segment values (Process, ProcessIgnorePause, PhysicsProcess, DeferredProcess).
  • Introduce CancelWith(Node...) lifecycle binding semantics and explain how node death cancels associated coroutines.
  • Align Godot docs with IYieldInstruction-based waits (Delay, WaitForSecondsRealtime, WaitOneFrame, WaitForEndOfFrame, etc.) and Task/event-bus waiting via core extensions.
  • Add coverage of coroutine handles and global control via Timing (Pause/Resume/Kill by handle/tag/all) and how to wait for events with WaitForEvent in a Godot context.
  • Replace prior context-aware/source-generator/logging/UI-binding best-practices with a more concise integration section for IContextAware command/query/publish coroutine helpers, plus a shortened related-docs list.
docs/zh-CN/godot/coroutine.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@deepsource-io

deepsource-io Bot commented Mar 12, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in d038b67...4362989 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
C# Mar 12, 2026 4:49a.m. Review ↗
Secrets Mar 12, 2026 4:49a.m. Review ↗

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我在这里给出了一些总体反馈:

  • 在 Godot 部分关于 CancelWith(...) 的说明中,建议更明确地界定节点何时被视为“失效”(例如:退出场景树 vs 被释放),这样用户就能清楚包装后的协程究竟会在什么时候停止。
  • 在 Task 桥接的示例中,现在同时展示了 AsCoroutineInstructionStartTaskAsCoroutine/ToCoroutineEnumerator;如果能简单说明在什么情况下应优先选择哪一种模式(例如:嵌入到现有协程中 vs 启动一个顶层协程),会对读者更有帮助。
给 AI Agent 的提示词
Please address the comments from this code review:

## Overall Comments
- In the Godot section on `CancelWith(...)`, consider clarifying exactly what counts as a node becoming "失效" (e.g., exiting the scene tree vs. being freed) so users know when the wrapped coroutine will actually stop.
- In the Task-bridging examples, you now show both `AsCoroutineInstruction` and `StartTaskAsCoroutine`/`ToCoroutineEnumerator`; it may help readers if you briefly spell out when to prefer each pattern (e.g., embedding inside an existing coroutine vs. starting a top-level coroutine).

Sourcery 对开源项目是免费的——如果你觉得我们的代码评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的代码评审。
Original comment in English

Hey - I've left some high level feedback:

  • In the Godot section on CancelWith(...), consider clarifying exactly what counts as a node becoming "失效" (e.g., exiting the scene tree vs. being freed) so users know when the wrapped coroutine will actually stop.
  • In the Task-bridging examples, you now show both AsCoroutineInstruction and StartTaskAsCoroutine/ToCoroutineEnumerator; it may help readers if you briefly spell out when to prefer each pattern (e.g., embedding inside an existing coroutine vs. starting a top-level coroutine).
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the Godot section on `CancelWith(...)`, consider clarifying exactly what counts as a node becoming "失效" (e.g., exiting the scene tree vs. being freed) so users know when the wrapped coroutine will actually stop.
- In the Task-bridging examples, you now show both `AsCoroutineInstruction` and `StartTaskAsCoroutine`/`ToCoroutineEnumerator`; it may help readers if you briefly spell out when to prefer each pattern (e.g., embedding inside an existing coroutine vs. starting a top-level coroutine).

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

- 添加了 AsCoroutineInstruction()、ToCoroutineEnumerator() 和 StartTaskAsCoroutine()
  的使用场景说明
- 优化了等待异步方法的文档描述,明确不同 API 的适用场景
- 详细说明了 CancelWith 方法的节点有效性判断机制和停止条件
- 补充了 Godot 协程中 Task 转协程的具体使用建议
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant