<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] ### **什么是 GMP?** > 先解釋代表的意思: G:Goroutine,實際上我們每次調用`go func`就是生成了一個 G。 P:Processor,處理器,一般 P 的數量就是處理器的核數,可以通過`GOMAXPROCS`進行修改。 M:Machine,系統線程。 > 再說GMP模型構成 在Go中,**線程是運行goroutine的實體,調度器的功能是把可運行的goroutine分配到工作線程上** ![](https://img.kancloud.cn/38/f8/38f83e7e7cffa0dfd2e22795cde4244b_1024x768.png) 1. **全局隊列**(Global Queue):存放等待運行的G。 2. **P的本地隊列**:同全局隊列類似,存放的也是等待運行的G,存的數量有限,不超過256個。新建G'時,G'優先加入到P的本地隊列,如果隊列滿了,則會把本地隊列中一半的G移動到全局隊列。 3. **P列表**:所有的P都在程序啟動時創建,并保存在數組中,最多有`GOMAXPROCS`(可配置)個。 4. **M**:線程想運行任務就得獲取P,從P的本地隊列獲取G,P隊列為空時,M也會嘗試從全局隊列**拿**一批G放到P的本地隊列,或從其他P的本地隊列**偷**一半放到自己P的本地隊列。M運行G,G執行之后,M會從P獲取下一個G,不斷重復下去。 > 最后說調度流程 ![](https://img.kancloud.cn/f8/33/f833f08292f506ea308a4f8972aa0486_1920x1080.png) 1、 GPM 的調度流程從 go func()開始創建一個 goroutine,新建的G優先放入P的本地隊列保存待執行的 goroutine(流程 2),當 M 綁定的 P 的的局部隊列已經滿了之后就會把 goroutine 放到全局隊列(流 程 2-1) 2、每個 P 和一個 M 綁定,M 是真正的執行 P 中 goroutine 的實體(流程 3), M 從綁定的 P 中的局部隊列獲取 G 來執行 3、當 M 綁定的 P 的局部隊列為空時,M 會從全局隊列獲取到本地隊列來執行 G (流程 3.1),當從全局隊列中沒有獲取到可執行的 G 時候,M 會從其他 P 的局部隊列中偷取 G 來執行(流程 3.2),這種從其他 P 偷的方式稱為 work stealing 4、一個M調度G執行的過程是一個循環機制 5、 當 G 因系統調用(syscall)阻塞時會阻塞 M,此時 P 會和 M 解綁即 hand off,并尋找新的空閑的 M,若沒有空閑的 M 就會新建一個 M(流程 5.1) 6、當 G 因 channel 或者 network I/O 阻塞時,不會阻塞 M,M 會尋找其他的 G;當阻塞的 G 恢復后會重新進入 runnable 進入 P 隊列等待執 行(流程 5.3) 7、 當M系統調用結束時候,這個G會嘗試獲取一個空閑的P執行,并放入到這個P的本地隊列。如果獲取不到P,則將G放入全局隊列,等待被其他的P調度。然后M將進入緩存池睡眠。 ### **搶占調度方式** >協作式的搶占式調度 程序只能依靠 Goroutine 主動讓出 CPU 資源才能觸發調度,長時間占用線程,會造成其他Goroutine饑餓 >基于信號的搶占式調度(反應可能遲鈍) 通過 sysmon 監控實現的搶占式調度,最快20us,最慢10-20ms ### **G-M-P的數量關系** * M:有限制,默認數量限制是 10000,可調整。(debug.SetMaxThreads 設置) * G:沒限制,但受內存影響。 ~~~ 假設一個 Goroutine 創建需要 4k: 4k * 80,000 = 320,000k ≈ 0.3G內存 4k * 1,000,000 = 4,000,000k ≈ 4G內存 以此就可以相對計算出來一臺單機在通俗情況下,所能夠創建 Goroutine 的大概數量級別。 注:Goroutine 創建所需申請的 2-4k 是需要連續的內存塊。 ~~~ * P:受本機的核數影響,可大可小,不影響 G 的數量創建。(**`GOMAXPROCS`**) ### **GMP 調度過程中存在哪些阻塞** * I/O,select * block on syscall * channel * 等待鎖 * runtime.Gosched() ### **Sysmon 有什么作用** Sysmon 也叫監控線程,變動的周期性檢查 * 釋放閑置超過 5 分鐘的 span 物理內存; * 如果超過 2 分鐘沒有垃圾回收,強制執行; * 將長時間未處理的 netpoll 添加到全局隊列; 30 * 向長時間運行的 G 任務發出搶占調度(超過 10ms 的 g,會進行 retake); * 收回因 syscall 長時間阻塞的 P;
                  <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>

                              哎呀哎呀视频在线观看