协程 的 实现方法

能够先看看我以前写的  《再见 异步回调, 再见 Async Await, 10 万 个 协程 的 时代 来 了》   http://www.javashuo.com/article/p-kkudjbvr-cx.html   ,html

 

要实现 协程 ,  须要 语言 本身 实现一个 线程池,  而后 把 协程 放到 线程 里 执行  。编程

 

协程 切换 就是 把 当前 协程 的 栈顶 和 指令计数器 保存起来 ,  在 操做系统 里,   栈顶 和 指令计数器 就是 线程  上下文, 由 操做系统 保存,闭包

对于  协程,   语言 能够 在 堆 里 建立一个 协程 对象,  协程 对象 有 一个 栈顶 字段 和 一个 指令计数器 字段,架构

协程 的 栈顶 和 指令计数器 就能够保存到 栈顶 字段 和 指令计数器 字段 里,并发

到 下次 轮到 这个 协程 执行时,  再 把 栈顶 字段 和 指令计数器 字段 的 值 赋值给 寄存器,异步

这样 就能够 实现 协程 的 切换 了 。async

 

和 操做系统 相似,   语言 须要 维护 一个 协程 的 就绪队列 和 一个 挂起队列 ,    协程 在 等待 其它 协程 或者 线程 时, 须要 挂起, 这样 协程 对象 会 添加到 挂起队列,  当 其它 协程 或 线程 完成时, 会 将 协程 从 挂起 队列 移除, 添加 到 就绪队列, 这样 不久的未来 就能够 继续 执行 协程  。函数

 

对 就绪队列 和 挂起队列 的 添加 和 移除 操做 是一个 队列 的 操做,   考虑到 并发,  须要在 添加 和 移除 时 Lock(同步 / 互斥),  这可使用 CAS lock ,  而不是 操做系统 提供的 lock,     CAS 的 性能 更高,    new 操做 应该 就是 使用 CAS lock 来 修改 堆 表,   这样的话,  协程 挂起 和 唤醒 的 时间花费 和 new 操做 差很少  。性能

 

总的来讲,   协程 切换 的 时间花费 至关于 执行了 一段 很短 的 代码   。spa

 

为何要 语言 本身实现一个 线程池?   而不是 使用 操做系统 提供 的 线程池,   由于 使用 操做系统 提供的 线程池 就成了   async await   了   。 ^^

 

这又涉及到  协程 和  async await   的  区别 的 问题,    这个问题 和   为何 要 语言 本身 实现一个 线程池 差很少 是 同一个 问题  。

 

操做系统 的 线程池 的 任务单位 是一个 函数,   因此,   async await  使用 操做系统 的 线程池 的 话,  就须要 把 一个 方法 内 跨线程 调用 前 和 后 的 两部分 代码 切割 为 2 个 函数 ,    在 语言 的 层面 ,  这 2 个 函数 自己是一个 方法(函数),   因此 函数 2 能够 访问 函数 1 中 的 变量,   但 既然 切割 成了 2 个 函数 , 那么 要 让 函数 2 能够 访问 函数 1 中 的 变量,  就须要      闭包  状态机     等 方式 来 共享  这些 变量   。

 

对于 协程 ,    因为 是 本身 实现 的 线程池 ,   因此 把 协程 放在 线程 里 执行 不须要 以 函数 为 单位,  而是 载入 协程 的 上下文(栈顶  指令计数器) 到 寄存器, 而后 继续 执行 指令 就能够,  这些是 语言 在 汇编 层面 完成的,   就是说 是 语言 的 编译器 在 生成 目标代码(汇编)时 将 代码 编译 成 这样的  。

 

因此,   对于 async await  来讲, 把 一个 方法 切割成 函数1 和 函数2   两部分 ,    那么 执行 函数1 和 函数2 时 ,   二者 有 各自 的 栈顶 ,   是 2 次 函数调用,

而 对于 协程,   跨协程 / 跨线程  调用 前 后 的 2 部分 代码 在 执行时 的 栈顶 是 同一个,  是一次 完整的 函数调用  。      只不过 在 跨协程 / 跨线程  调用 时   发生了 “切换”  ,     即把 寄存器 保存的 栈顶 做为 上下文 保存到 协程 对象 里 ,    当 切换回来 时 再 从 协程 对象 的 栈顶 字段 赋值 给 寄存器 ,   而后 接着 执行  。

挂起前 和 恢复执行后 的  栈顶 是 同一个,    或者说,   跨协程 / 跨线程  调用 前 后 的 2 部分 代码 的 栈顶 是 同一个,   这 2 部分 代码 是 同一次 函数调用  。

这就是    协程    和   async await   的 本质区别 之一  。

 

协程 和 async await  的 另外一个 本质区别 是   设计理念   的 不一样  ,    async await  是把 异步 变得 看起来 像 同步,   而 协程 是 让 切换 轻量化 、平常化  。

因此, 协程 要 实现的,  是 恢复 传统 的 编程 模型,   同步 是 同步 ,    异步 是 异步  ,    协程 的 数量 没有 限制,  和 对象 同样,   对象 的 数量 能有多少, 协程 的 数量 就能 有多少,  协程 的 切换 至关于 new 一个对象,   这样 就 能  恢复     传统的 正常的 常规的  编程 模型 范式 架构 思惟 思潮    。

 

这样 就 不须要  异步回调流   为了 节省 线程  就 把  同步 调用 变 异步 ,      再 经过  async await   把 异步 代码 变得 “像” 同步代码   。

这 很 糟糕    。

 

也正由于这样 ,     因此 我 说     异步回调流  和  async await    只是一个 过渡,  不可能 长期 霸占 程序界,

并且 ,   async  await  是 怪物  。          哈哈哈哈哈

相关文章
相关标签/搜索