協程 的 實現方法

能夠先看看我以前寫的  《再見 異步回調, 再見 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  是 怪物  。          哈哈哈哈哈

相關文章
相關標籤/搜索