写 这篇 文章 的 起因 是 刚刚 看了 知乎 《C++20协程原理和应用》 https://zhuanlan.zhihu.com/p/497224333 。
《C++20协程原理和应用》 开头一段
“
协程分为无栈协程和有栈协程两种,无栈指可挂起/恢复的函数,有栈协程则相当于用户态线程。有栈协程切换的成本是用户态线程切换的成本,而无栈协程切换的成本则相当于函数调用的成本。
无栈协程和线程的区别:无栈协程只能被线程调用,本身并不抢占内核调度,而线程则可抢占内核调度。
”
我又往下看了一些 内容 , 以 我 的 想法, 无栈协程 就是 状态机, 有栈协程 就是 协程, 关于 状态机 和 协程 的 比较, 我在 前几天 写的 《协程 的 主要作用 是 让 单核 GC 变成 单线程 GC》 https://www.cnblogs.com/KSongKing/p/16181359.html 里 讲过 。
状态机 可以 让 编译器 对 函数 统一 做 尽可能深化 的 内联 和 寄存器优化 (寄存器布局) 。
现在, 还可以加上一条, 状态机 可以减少 Cache Miss , 这一条 是 《C++20协程原理和应用》 里 说 的 。
当然, 状态机 也可以减少 协程 / 线程 切换时 栈 载入载出 Cache 的 次数 。
协程 和 线程 的 比较 , 大概是 协程 切换 的 工作 只需要 保存 / 恢复 上下文, 而 线程切换 除了 保存 / 恢复 上下文, 还要 进行调度, 就是 操作系统 要 计算 线程 的 优先级, 比如 通常 是 “抢占式多任务” 的 说法 吧, 就是 哪个 线程 在 过去 的 一段时间 里 对 CPU 的 使用 越多, 就 优先 让 哪个 线程 运行, 也可以说, 对 CPU 使用越多 的 线程 就 可以 获得 越多 的 时间片, 越 优先 运行 。
这个 计算 优先级 的 算法, 就是 查 一棵 二叉树 。
也就是说, 线程切换 除了 保存 / 恢复 上下文, 还要 多做 这个 查 二叉树 的 工作 。 实际上 也许还有 其它 一些 工作 和 性能开销, 比如 线程切换 要 先 切换到 系统进程, 这本身 就是 一次 切换, 也要 保存 / 恢复 上下文, 然后 系统进程 调度, 查 二叉树, 再 切换线程 。 性能开销 比如 需要 把 系统进程 的 一些 数据 载入 Cache, 比如 二叉树 。
线程 比 协程 多了一个 查 二叉树 的 工作 这一点, 在 2020 年底 到 2021 上半年 在 QQ 群 里 讨论 ILBC / D++ 的 期间, 说到过 。