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