<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Goroutine 的切換過程涉及了什么

          共 3034字,需瀏覽 7分鐘

           ·

          2021-03-07 22:23

          點擊上方藍色“Go語言中文網(wǎng)”關(guān)注,每天一起學 Go

          Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

          本文基于 Go 1.13 版本。

          Goroutine 很輕,它只需要 2Kb 的內(nèi)存堆棧即可運行。另外,它們運行起來也很廉價,將一個 Goroutine 切換到另一個的過程不牽涉到很多的操作。在深入 Goroutine 切換過程之前,讓我們回顧一下 Goroutine 的切換在更高的層次上是如何進行的。

          在繼續(xù)閱讀本文之前,我強烈建議您閱讀我的文章 Go:Goroutine、操作系統(tǒng)線程和 CPU 管理[1] 以了解本文中涉及的一些概念。

          案例

          Go 根據(jù)兩種斷點將 Goroutine 調(diào)度到線程上:

          • 當 Goroutine 因為系統(tǒng)調(diào)用、互斥鎖或通道而被阻塞時,goroutine 將進入睡眠模式(等待隊列),并允許 Go 調(diào)度運行另一個處于就緒狀態(tài)的 goroutine;
          • 在函數(shù)調(diào)用時,如果 Goroutine 必須增加其堆棧,這會使 Go 調(diào)度另一個 Goroutine 以避免運行中的 Goroutine 獨占 CPU 時間片;

          在這兩種情況下,運行調(diào)度程序的 g0 會替換當前的 goroutine,然后選出下一個將要運行的 Goroutine 替換 g0 并在線程上運行。

          有關(guān) g0 的更多信息,建議您閱讀我的文章 Go:特殊的 Goroutine g0[2]。

          將一個運行中的 Goroutine 切換到另一個的過程涉及到兩個切換:

          • 將運行中的 g 切換到 g0

          • g0 切換到下一個將要運行的 g

          在 Go 中,goroutine 的切換相當輕便,其中需要保存的狀態(tài)僅僅涉及以下兩個:

          • Goroutine 在停止運行前執(zhí)行的指令,程序當前要運行的指令是記錄在程序計數(shù)器(PC)中的, Goroutine 稍后將在同一指令處恢復(fù)運行;

          • Goroutine 的堆棧,以便在再次運行時還原局部變量;

          讓我們看看實際情況下的切換是怎樣進行的。

          程序計數(shù)器

          這里通過基于通道的 生產(chǎn)者/消費者模式 來舉例說明,其中一個 Goroutine 產(chǎn)生數(shù)據(jù),而另一些則消費數(shù)據(jù),代碼如下:

          消費者僅僅是打印從 0 到 99 的偶數(shù)。我們將注意力放在第一個 goroutine(生產(chǎn)者)上,它將數(shù)字添加到緩沖區(qū)。當緩沖區(qū)已滿時,它將在發(fā)送消息時被阻塞。此時,Go 必須切換到 g0 并調(diào)度另一個 Goroutine 來運行。

          如前所述,Go 首先需要保存當前執(zhí)行的指令,以便稍后在同一條指令上恢復(fù) goroutine。程序計數(shù)器(PC)保存在 Goroutine 的內(nèi)部結(jié)構(gòu)中:

          可以通過 go tool objdump 命令找到對應(yīng)的指令及其地址,這是生產(chǎn)者的指令:

          程序逐條指令的執(zhí)行直到在函數(shù) runtime.chansend1 處阻塞在通道上。Go 將當前程序計數(shù)器保存到當前 Goroutine 的內(nèi)部屬性中。在我們的示例中,Go 使用運行時的內(nèi)部地址 0x4268d0 和方法 runtime.chansend1 保存程序計數(shù)器:

          然后,當 g0 喚醒 Goroutine 時,它將在同一指令處繼續(xù)執(zhí)行,繼續(xù)將數(shù)值循環(huán)的推入通道?,F(xiàn)在,讓我們將視線移到 Goroutine 切換期間堆棧的管理。

          堆棧

          在被阻塞之前,正在運行的 Goroutine 具有其原始堆棧,該堆棧包含臨時存儲器,例如變量 i

          然后,當它在通道上阻塞時,goroutine 將切換到 g0 及其堆棧(更大的堆棧):

          在切換之前,堆棧將被保存,以便在 Goroutine 再次運行時進行恢復(fù):

          現(xiàn)在,我們對 Goroutine 切換中涉及的不同操作有了一個完整的了解,讓我們繼續(xù)看看它是如何影響性能的。

          我們應(yīng)該注意,諸如 arm 等 CPU 架構(gòu)需要再保存一個寄存器,即 LR 鏈接寄存器。

          性能

          我們?nèi)匀皇褂蒙鲜龅某绦騺頊y量一次切換所需的時間。但是,由于切換時間取決于尋找下一個要調(diào)度的 Goroutine 所花費的時間,因此無法提供完美的性能視圖。在函數(shù)調(diào)用情況下進行的切換要比阻塞在通道上的切換執(zhí)行更多的操作,這也會影響到性能。

          讓我們總結(jié)一下我們將要測量的操作:

          • 當前 g 阻塞在通道上并切換到 g0
            • PC 和堆棧指針一起保存在內(nèi)部結(jié)構(gòu)中
            • g0 設(shè)置為正在運行的 goroutine
            • g0 的堆棧替換當前堆棧
          • g0 尋找新的 Goroutine 來運行;
          • g0 使用所選的 Goroutine 進行切換:
            • PC 和堆棧指針是從其內(nèi)部結(jié)構(gòu)中獲取的
            • 程序跳轉(zhuǎn)到對應(yīng)的 PC 地址

          結(jié)果如下:

          gg0 或從 g0g 的切換是相當迅速的,它們只包含少量固定的指令。相反,對于調(diào)度階段,調(diào)度程序需要檢查許多資源以便確定下一個要運行的 goroutine,根據(jù)程序的不同,此階段可能會花費更多的時間。

          該基準測試給出了性能的數(shù)量級估計,由于沒有標準的工具可以衡量它,所以我們并不能完全依賴于這個結(jié)果。此外,性能也取決于 CPU 架構(gòu)、機器(本文使用的機器是 Mac 2.9 GHz 雙核 Intel Core i5)以及正在運行的程序。


          via: https://medium.com/a-journey-with-go/go-what-does-a-goroutine-switch-actually-involve-394c202dddb7

          作者:Vincent Blanchon[3]譯者:anxk[4]校對:polaris1119[5]

          本文由 GCTT[6] 原創(chuàng)編譯,Go 中文網(wǎng)[7] 榮譽推出

          參考資料

          [1]

          Go:Goroutine、操作系統(tǒng)線程和 CPU 管理: https://medium.com/a-journey-with-go/go-goroutine-os-thread-and-cpu-management-2f5a5eaf518a

          [2]

          Go:特殊的 Goroutine g0: https://medium.com/a-journey-with-go/go-g0-special-goroutine-8c778c6704d8

          [3]

          Vincent Blanchon: https://medium.com/@blanchon.vincent

          [4]

          anxk: https://github.com/anxk

          [5]

          polaris1119: https://github.com/polaris1119

          [6]

          GCTT: https://github.com/studygolang/GCTT

          [7]

          Go 中文網(wǎng): https://studygolang.com/



          推薦閱讀


          福利

          我為大家整理了一份從入門到進階的Go學習資料禮包,包含學習建議:入門看什么,進階看什么。關(guān)注公眾號 「polarisxu」,回復(fù) ebook 獲??;還可以回復(fù)「進群」,和數(shù)萬 Gopher 交流學習。

          瀏覽 62
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  jizz日韩| 国产人妻国产毛片 | 欧美第一草草 | 樱桃视频91 | 波多野结衣大香蕉 |