<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 功能強大 支持多語言、二開方便! 廣告
                ### go協程調度 ### 核心圖 ![調度圖](https://segmentfault.com/img/remote/1460000015352988?w=786&h=683) ![運行圖](https://segmentfault.com/img/remote/1460000015352989?w=672&h=384) ![](https://ws1.sinaimg.cn/large/e5320b2aly1fv6vtv5mjxj20fa0b4myk.jpg) ![](https://ws1.sinaimg.cn/large/e5320b2aly1fv6vuds7fjj20zk0mxdgx.jpg) ### G-P-M 模型調度 Go調度器工作時會維護兩種用來保存G的任務隊列:一種是一個Global任務隊列,一種是每個P維護的Local任務隊列。 當通過go關鍵字創建一個新的goroutine的時候,它會優先被放入P的本地隊列。為了運行goroutine,M需要持有(綁定)一個P,接著M會啟動一個OS線程,循環從P的本地隊列里取出一個goroutine并執行。當然還有上文提及的 work-stealing調度算法:當M執行完了當前P的Local隊列里的所有G后,P也不會就這么在那躺尸啥都不干,它會先嘗試從Global隊列尋找G來執行,如果Global隊列為空,它會隨機挑選另外一個P,從它的隊列里中拿走一半的G到自己的隊列中執行。 如果一切正常,調度器會以上述的那種方式順暢地運行,但這個世界沒這么美好,總有意外發生,以下分析goroutine在兩種例外情況下的行為。 Go runtime會在下面的goroutine被阻塞的情況下運行另外一個goroutine: - blocking syscall (for example opening a file) - network input - channel operations - primitives in the sync package 這四種場景又可歸類為兩種類型: ### 用戶態阻塞/喚醒 當goroutine因為channel操作或者network I/O而阻塞時(實際上golang已經用netpoller實現了goroutine網絡I/O阻塞不會導致M被阻塞,僅阻塞G,這里僅僅是舉個栗子),對應的G會被放置到某個wait隊列(如channel的waitq),該G的狀態由_Gruning變為_Gwaitting,而M會跳過該G嘗試獲取并執行下一個G,如果此時沒有runnable的G供M運行,那么M將解綁P,并進入sleep狀態;當阻塞的G被另一端的G2喚醒時(比如channel的可讀/寫通知),G被標記為runnable,嘗試加入G2所在P的runnext,然后再是P的Local隊列和Global隊列。 ### 系統調用阻塞 當G被阻塞在某個系統調用上時,此時G會阻塞在_Gsyscall狀態,M也處于 block on syscall 狀態,此時的M可被搶占調度(可以搶占其他M):執行該G的M會與P解綁,而P則嘗試與其它idle的M綁定,繼續執行其它G。如果沒有其它idle的M,但P的Local隊列中仍然有G需要執行,則創建一個新的M;當系統調用完成后,G會重新嘗試獲取一個idle的P進入它的Local隊列恢復執行,如果沒有idle的P,G會被標記為runnable加入到Global隊列。(全局隊列用武之地) 以上就是從宏觀的角度對Goroutine和它的調度器進行的一些概要性的介紹,當然,Go的調度中更復雜的搶占式調度、阻塞調度的更多細節,大家可以自行去找相關資料深入理解,本文只講到Go調度器的基本調度過程,為后面自己實現一個Goroutine Pool提供理論基礎,這里便不再繼續深入上述說的那幾個調度了,事實上如果要完全講清楚Go調度器,一篇文章的篇幅也實在是捉襟見肘,所以想了解更多細節的同學可以去看看Go調度器 G-P-M 模型的設計者 Dmitry Vyukov 寫的該模型的設計文檔《Go Preemptive Scheduler Design》以及直接去看源碼,G-P-M模型的定義放在src/runtime/runtime2.go里面,而調度過程則放在了src/runtime/proc.go里。 ### 問題? #### 0.go協程阻塞時如何進行調度? > 在程序中任何對系統 API 的調用,都會被 runtime 層攔截來方便調度。 > Goroutine 在 system call 和 channel call 時都可能發生阻塞,但這兩種阻塞發生后,處理方式又不一樣的。 > 1.當程序發生 system call,M 會發生阻塞,同時喚起(或創建)一個新的 M 繼續執行其他的 G。當MO返回時,它必須嘗試取得一個context P來運行goroutine,一般情況下,它會從其他的OS線程那里steal偷一個context過來,如果沒有偷到的話,它就把goroutine放在一個global runqueue里,然后自己就去睡大覺了(放入線程緩存里)。Contexts們也會周期性的檢查global runqueue,否則global runqueue上的goroutine永遠無法執行。 > 2.當程序發起一個 channel call,程序可能會阻塞,但不會阻塞 M,G 的狀態會設置為 waiting,M 繼續執行其他的 G。當 G 的調用完成,會有一個可用的 M 繼續執行它。 #### 1.go為什么要實現自己的協程調度,而不用系統調度? > 1.線程較多時,開銷較大。 > 2.OS 的調度,程序不可控。而 Go GC 需要停止所有的線程,使內存達到一致狀態。 #### 2.GM為啥不行?P有什么作用? > 1.每個 P 都有一個隊列,用來存正在執行的 G。避免 Global Sched Lock。 > 2.每個 M 運行都需要一個 MCache 結構。M Pool 中通常有較多 M,但執行的只有幾個,為每個池子中的每個 M 分配一個 MCache 則會形成不必要的浪費,通過把 cache 從 M 移到 P,每個運行的 M 都有關聯的 P,這樣只有運行的 M 才有自己的 MCache。 #### 3.Goroutine vs OS thread 有什么區別? > 其實 goroutine 用到的就是線程池的技術,當 goroutine 需要執行時,會從 thread pool 中選出一個可用的 M 或者新建一個 M。而 thread pool 中如何選取線程,擴建線程,回收線程,Go Scheduler 進行了封裝,對程序透明,只管調用就行,從而簡化了 thread pool 的使用。 #### 4.sysmon功能是什么? >釋放閑置超過5分鐘的span物理內存; >如果超過2分鐘沒有垃圾回收,強制執行; >將長時間未處理的netpoll結果添加到任務隊列; >向長時間運行的G任務發出搶占調度; >收回因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>

                              哎呀哎呀视频在线观看