协程是一种特殊的函数,可以在函数执行过程中暂停和恢复。协程可以用于实现异步编程,特别是在Unity中,协程可以用于实现动画、移动、等待等操作。
用 Mermaid 绘制一个协程的执行流程图,以 say_hello
协程为例:
sequenceDiagram
participant Main as 主线程
participant Task as Task对象
participant Promise as 允诺对象
participant Coroutine as 协程函数体
participant Async as 异步任务
Main->>Task: 创建协程(say_hello)
Note over Task: 1. 创建允诺对象
2. 创建协程句柄 Task->>Promise: initial_suspend() Promise-->>Task: 挂起 Main->>Task: resume() Task->>Coroutine: 开始执行 Note over Coroutine: 输出"Starting [name]" Coroutine->>Async: 创建异步任务 Async->>Async: 执行睡眠 loop 等待异步任务完成 Coroutine->>Coroutine: co_await suspend_always Coroutine-->>Task: 挂起 Task->>Main: 返回控制权 Main->>Task: resume() Task->>Coroutine: 恢复执行 Coroutine->>Async: 检查是否完成 end Async-->>Coroutine: 任务完成 Coroutine->>Coroutine: 输出"Hello [name]" Coroutine->>Promise: co_return Promise->>Promise: final_suspend() Promise-->>Task: 标记完成 Task->>Main: 协程结束
2. 创建协程句柄 Task->>Promise: initial_suspend() Promise-->>Task: 挂起 Main->>Task: resume() Task->>Coroutine: 开始执行 Note over Coroutine: 输出"Starting [name]" Coroutine->>Async: 创建异步任务 Async->>Async: 执行睡眠 loop 等待异步任务完成 Coroutine->>Coroutine: co_await suspend_always Coroutine-->>Task: 挂起 Task->>Main: 返回控制权 Main->>Task: resume() Task->>Coroutine: 恢复执行 Coroutine->>Async: 检查是否完成 end Async-->>Coroutine: 任务完成 Coroutine->>Coroutine: 输出"Hello [name]" Coroutine->>Promise: co_return Promise->>Promise: final_suspend() Promise-->>Task: 标记完成 Task->>Main: 协程结束
- 创建阶段:
- 主线程创建协程
- 创建允诺对象和协程句柄
- 初始挂起
- 执行阶段:
- 协程开始执行
- 创建异步任务
- 在等待期间反复挂起和恢复
- 完成阶段:
- 异步任务完成
- 输出完成信息
- 最终挂起
- 标记协程完成
这个流程展示了协程如何:
- 在需要等待时挂起
- 让出控制权给主线程
- 在适当的时候恢复执行
- 最终完成并清理资源
这就是为什么协程可以高效地处理异步操作 - 它不会阻塞线程,而是在等待时让出控制权,让其他任务可以执行。
gantt
title 协程和线程配合执行时间线
dateFormat HH:mm:ss
section 主线程
创建协程 :00:00:00, 1s
创建其他协程 :00:00:01, 2s
等待完成 :00:00:03, 2s
section Alice协程
初始挂起 :00:00:00, 1s
输出开始 :00:00:01, 1s
等待循环 :00:00:02, 2s
输出完成 :00:00:04, 1s
section Alice异步线程
开始睡眠 :00:00:01, 2s
完成睡眠 :00:00:03, 1s
gantt
title 三个协程的线程执行时间线
dateFormat HH:mm:ss
section 主线程
创建协程 :00:00:00, 1s
等待完成 :00:00:01, 3s
section Alice协程 (2秒)
创建线程1 :00:00:00, 1s
线程1睡眠 :00:00:01, 2s
完成 :00:00:03, 1s
section Bob协程 (1秒)
创建线程2 :00:00:00, 1s
线程2睡眠 :00:00:01, 1s
完成 :00:00:02, 1s
section Charlie协程 (3秒)
创建线程3 :00:00:00, 1s
线程3睡眠 :00:00:01, 3s
完成 :00:00:04, 1s
sequenceDiagram
participant Main as 主线程
participant Task as 协程
Main->>Task: 创建协程
Note over Task: 初始状态:暂停
Main->>Task: wait_for_all开始
Main->>Task: resume() 第一次
Note over Task: 执行到co_await挂起点
loop 等待循环
Main->>Task: 检查是否完成
alt 未完成
Main->>Task: resume() 再次尝试
else 完成
Main->>Main: 退出循环
end
end