<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 功能強大 支持多語言、二開方便! 廣告
                Goroutine協程: 協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧。 因此,協程能保留上一次調用時的狀態(即所有局部狀態的一個特定組合),每次過程重入時,就相當于進入上一次調用的狀態,換種說法:進入上一次離開時所處邏輯流的位置。 線程和進程的操作是由程序觸發系統接口,最后的執行者是系統;協程的操作執行者則是用戶自身程序,goroutine也是協程。 groutine能擁有強大的并發實現是通過GPM調度模型實現. Go的調度器內部有四個重要的結構:M,P,S,Sched,如上圖所示(Sched未給出). * M: M代表內核級線程,一個M就是一個線程,goroutine就是跑在M之上的;M是一個很大的結構,里面維護小對象內存cache(mcache)、當前執行的goroutine、隨機數發生器等等非常多的信息. * G: 代表一個goroutine,它有自己的棧,instruction pointer和其他信息(正在等待的channel等等),用于調度. * P: P全稱是Processor,邏輯處理器,它的主要用途就是用來執行goroutine的,所以它也維護了一個goroutine隊列,里面存儲了所有需要它來執行的goroutine. * Sched:代表調度器,它維護有存儲M和G的隊列以及調度器的一些狀態信息等. Go中的GPM調度: 新創建的G 會先保存在 P 的本地隊列中,如果 P 的本地隊列已經滿了就會保存在全局的隊列中,最終等待被邏輯處理器P執行即可。 在M與P綁定后,M會不斷從P的Local隊列中無鎖地取出G,并切換到G的堆棧執行,當P的Local隊列中沒有G時,再從Global隊列中獲取一個G,當Global隊列中也沒有待運行的G時,則嘗試從其它的P竊取部分G來執行相當于P之間的負載均衡。 [![](https://github.com/KeKe-Li/data-structures-questions/raw/master/src/images/65.jpg)](https://github.com/KeKe-Li/data-structures-questions/blob/master/src/images/65.jpg) 從上圖中可以看到,有2個物理線程M,每一個M都擁有一個處理器P,每一個也都有一個正在運行的goroutine。P的數量可以通過GOMAXPROCS()來設置,它其實也就代表了真正的并發度,即有多少個goroutine可以同時運行。 圖中灰色的那些goroutine并沒有運行,而是出于ready的就緒態,正在等待被調度。P維護著這個隊列(稱之為runqueue),Go語言里,啟動一個goroutine很容易:go function 就行,所以每有一個go語句被執行,runqueue隊列就在其末尾加入一個goroutine,在下一個調度點,就從runqueue中取出(如何決定取哪個goroutine?)一個goroutine執行。 當一個OS線程M0陷入阻塞時,P轉而在運行M1,圖中的M1可能是正被創建,或者從線程緩存中取出。 [![](https://github.com/KeKe-Li/data-structures-questions/raw/master/src/images/60.jpg)](https://github.com/KeKe-Li/data-structures-questions/blob/master/src/images/60.jpg) 當M0返回時,它必須嘗試取得一個P來運行goroutine,一般情況下,它會從其他的OS線程那里拿一個P過來,如果沒有拿到的話,它就把goroutine放在一個`global runqueue`里,然后自己睡眠(放入線程緩存里)。所有的P也會周期性的檢查`global runqueue`并運行其中的goroutine,否則`global runqueue`上的goroutine永遠無法執行。 另一種情況是P所分配的任務G很快就執行完了(分配不均),這就導致了這個處理器P處于空閑的狀態,但是此時其他的P還有任務,此時如果global runqueue沒有任務G了,那么這個P就會從其他的P里偷取一些G來執行。 [![](https://github.com/KeKe-Li/data-structures-questions/raw/master/src/images/64.jpg)](https://github.com/KeKe-Li/data-structures-questions/blob/master/src/images/64.jpg) 通常來說,如果P從其他的P那里要拿任務的話,一般就拿`run queue`的一半,這就確保了每個OS線程都能充分的使用。 [![](https://github.com/KeKe-Li/data-structures-questions/raw/master/src/images/129.jpg)](https://github.com/KeKe-Li/data-structures-questions/blob/master/src/images/129.jpg)
                  <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>

                              哎呀哎呀视频在线观看