<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 調度器調度場景過程全解析 (1) 場景 1 P 擁有 G1,M1 獲取 P 后開始運行 G1,G1 使用 go func() 創建了 G2,為了局部性 G2 優先加入到 P1 的本地隊列。 ![](https://img.kancloud.cn/bb/81/bb81393ad3179b6a224c2558b348bcd4_1074x900.png) (2) 場景 2 G1 運行完成后 (函數:goexit),M 上運行的 goroutine 切換為 G0,G0 負責調度時協程的切換(函數:schedule)。從 P 的本地隊列取 G2,從 G0 切換到 G2,并開始運行 G2 (函數:execute)。實現了線程 M1 的復用。 ![](https://img.kancloud.cn/e8/29/e829f894a8bc41a5e85b5b22535da58f_1240x751.png) (3) 場景 3 假設每個 P 的本地隊列只能存 3 個 G。G2 要創建了 6 個 G,前 3 個 G(G3, G4, G5)已經加入 p1 的本地隊列,p1 本地隊列滿了。 ![](https://img.kancloud.cn/8d/9e/8d9e13490681c996ccf1348cf4b69d55_1104x1030.png) (4) 場景 4 G2 在創建 G7 的時候,發現 P1 的本地隊列已滿,需要執行負載均衡 (把 P1 中本地隊列中前一半的 G,還有新創建 G 轉移到全局隊列) > (實現中并不一定是新的 G,如果 G 是 G2 之后就執行的,會被保存在本地隊列,利用某個老的 G 替換新 G 加入全局隊列) ![](https://img.kancloud.cn/8e/01/8e01de2bbf8ce827ba701eb9e1a7c33c_1120x1068.png) 這些 G 被轉移到全局隊列時,會被打亂順序。所以 G3,G4,G7 被轉移到全局隊列。 (5) 場景 5 G2 創建 G8 時,P1 的本地隊列未滿,所以 G8 會被加入到 P1 的本地隊列。 ![](https://img.kancloud.cn/2f/ac/2face8532e205e6bcd5650129ed4dc80_1036x1048.png) G8 加入到 P1 點本地隊列的原因還是因為 P1 此時在與 M1 綁定,而 G2 此時是 M1 在執行。所以 G2 創建的新的 G 會優先放置到自己的 M 綁定的 P 上。 (6) 場景 6 規定:在創建 G 時,運行的 G 會嘗試喚醒其他空閑的 P 和 M 組合去執行。 ![](https://img.kancloud.cn/82/b9/82b99539174856017dad19a966f6898c_1240x689.png) 假定 G2 喚醒了 M2,M2 綁定了 P2,并運行 G0,但 P2 本地隊列沒有 G,M2 此時為自旋線程(沒有 G 但為運行狀態的線程,不斷尋找 G)。 (7) 場景 7 M2 嘗試從全局隊列 (簡稱 “GQ”) 取一批 G 放到 P2 的本地隊列(函數:findrunnable())。M2 從全局隊列取的 G 數量符合下面的公式: > n = min(len(GQ)/GOMAXPROCS + 1, len(GQ/2)) 至少從全局隊列取 1 個 g,但每次不要從全局隊列移動太多的 g 到 p 本地隊列,給其他 p 留點。這是從全局隊列到 P 本地隊列的負載均衡。 ![](https://img.kancloud.cn/db/93/db935f3e20de219fff8dd0d38a9549ef_1240x698.png) 假定我們場景中一共有 4 個 P(GOMAXPROCS 設置為 4,那么我們允許最多就能用 4 個 P 來供 M 使用)。所以 M2 只從能從全局隊列取 1 個 G(即 G3)移動 P2 本地隊列,然后完成從 G0 到 G3 的切換,運行 G3。 (8) 場景 8 假設 G2 一直在 M1 上運行,經過 2 輪后,M2 已經把 G7、G4 從全局隊列獲取到了 P2 的本地隊列并完成運行,全局隊列和 P2 的本地隊列都空了,如場景 8 圖的左半部分。 ![](https://img.kancloud.cn/44/9a/449a8d60db34a865dcc08c3ffa4947ae_1240x859.png) 全局隊列已經沒有 G,那 m 就要執行 work stealing (偷取):從其他有 G 的 P 哪里偷取一半 G 過來,放到自己的 P 本地隊列。P2 從 P1 的本地隊列尾部取一半的 G,本例中一半則只有 1 個 G8,放到 P2 的本地隊列并執行。 (9) 場景 9 G1 本地隊列 G5、G6 已經被其他 M 偷走并運行完成,當前 M1 和 M2 分別在運行 G2 和 G8,M3 和 M4 沒有 goroutine 可以運行,M3 和 M4 處于自旋狀態,它們不斷尋找 goroutine。 ![](https://img.kancloud.cn/55/6e/556ec5d39811c30083178a618dc3a8e0_1240x799.png) 為什么要讓 m3 和 m4 自旋,自旋本質是在運行,線程在運行卻沒有執行 G,就變成了浪費 CPU. 為什么不銷毀現場,來節約 CPU 資源。因為創建和銷毀 CPU 也會浪費時間,我們希望當有新 goroutine 創建時,立刻能有 M 運行它,如果銷毀再新建就增加了時延,降低了效率。當然也考慮了過多的自旋線程是浪費 CPU,所以系統中最多有 GOMAXPROCS 個自旋的線程 (當前例子中的 GOMAXPROCS=4,所以一共 4 個 P),多余的沒事做線程會讓他們休眠。 (10) 場景 10 ? 假定當前除了 M3 和 M4 為自旋線程,還有 M5 和 M6 為空閑的線程 (沒有得到 P 的綁定,注意我們這里最多就只能夠存在 4 個 P,所以 P 的數量應該永遠是 M>=P, 大部分都是 M 在搶占需要運行的 P),G8 創建了 G9,G8 進行了阻塞的系統調用,M2 和 P2 立即解綁,P2 會執行以下判斷:如果 P2 本地隊列有 G、全局隊列有 G 或有空閑的 M,P2 都會立馬喚醒 1 個 M 和它綁定,否則 P2 則會加入到空閑 P 列表,等待 M 來獲取可用的 p。本場景中,P2 本地隊列有 G9,可以和其他空閑的線程 M5 綁定。 ![](https://img.kancloud.cn/39/1b/391bdf400c570f60c25e676450ae4898_1240x701.png) (11) 場景 11 G8 創建了 G9,假如 G8 進行了非阻塞系統調用。 ![](https://img.kancloud.cn/6f/09/6f096484b33da3e099838d355dcb7a9b_1240x679.png) ? M2 和 P2 會解綁,但 M2 會記住 P2,然后 G8 和 M2 進入系統調用狀態。當 G8 和 M2 退出系統調用時,會嘗試獲取 P2,如果無法獲取,則獲取空閑的 P,如果依然沒有,G8 會被記為可運行狀態,并加入到全局隊列,M2 因為沒有 P 的綁定而變成休眠狀態 (長時間休眠等待 GC 回收銷毀)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看