您好,登錄后才能下訂單哦!
goroutine簡介
goroutine是go語言中最為NB的設計,也是其魅力所在,goroutine的本質是協程,是實現并行計算的核心。goroutine使用方式非常的簡單,只需使用go關鍵字即可啟動一個協程,并且它是處于異步方式運行,你不需要等它運行完成以后在執行以后的代碼。
go func()//通過go關鍵字啟動一個協程來運行函數
go routine的調度原理和操作系統的線層調度是比較相似的。這里我們將介紹go routine的相關知識。
goroutine(有人也稱之為協程)本質上go的用戶級線程的實現,這種用戶級線程是運行在內核級線程之上。當我們在go程序中創建goroutine的時候,我們的這些routine將會被分配到不同的內核級線程中運行。一個內核級線程可能會負責多個routine的運行。而保證這些routine在內內核級線程安全、公平、高效運行的工作,就由調度器來實現。
goroutine內部原理
概念介紹
在進行實現原理之前,了解下一些關鍵性術語的概念。
并發
一個cpu上能同時執行多項任務,在很短時間內,cpu來回切換任務執行(在某段很短時間內執行程序a,然后又迅速得切換到程序b去執行),有時間上的重疊(宏觀上是同時的,微觀仍是順序執行),這樣看起來多個任務像是同時執行,這就是并發。
并行
當系統有多個CPU時,每個CPU同一時刻都運行任務,互不搶占自己所在的CPU資源,同時進行,稱為并行。
進程
cpu在切換程序的時候,如果不保存上一個程序的狀態(也就是我們常說的context--上下文),直接切換下一個程序,就會丟失上一個程序的一系列狀態,于是引入了進程這個概念,用以劃分好程序運行時所需要的資源。因此進程就是一個程序運行時候的所需要的基本資源單位(也可以說是程序運行的一個實體)。
線程
cpu切換多個進程的時候,會花費不少的時間,因為切換進程需要切換到內核態,而每次調度需要內核態都需要讀取用戶態的數據,進程一旦多起來,cpu調度會消耗一大堆資源,因此引入了線程的概念,線程本身幾乎不占有資源,他們共享進程里的資源,內核調度起來不會那么像進程切換那么耗費資源。
協程
協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧。因此,協程能保留上一次調用時的狀態(即所有局部狀態的一個特定組合),每次過程重入時,就相當于進入上一次調用的狀態,換種說法:進入上一次離開時所處邏輯流的位置。線程和進程的操作是由程序觸發系統接口,最后的執行者是系統;協程的操作執行者則是用戶自身程序,goroutine也是協程。
Go調度的組成
Go的調度主要有四個結構組成,分別是:
Go程序的啟動過程
創建goroutine:
創建內核級線程M
內核級線程由go的運行時根據實際情況創建,我們無法再go中創建內核級線程。那什么時候回創建內核級線程呢?當前程序等待運行的goroutine數量達到一定數量及存在空閑(為被分配給M)的P的時候,Go運行時就會創建一些M,然后將空閑的P分配給新建的內核級線程M,接著才是獲取、運行goroutine。創建M的接口函數如下:
// 創建M的接口函數 void newm(void (*fn)(void), P *p) // 分配P給M if(m != &runtime·m0) {Â acquirep(m->nextp); m->nextp = nil; } // 獲取goroutine并開始運行 schedule();
M的運行
static void schedule(void) { G *gp; gp = runqget(m->p); if(gp == nil) gp = findrunnable(); // 如果P的類別不止一個goroutine,且調度器中有空閑的的P,就喚醒其他內核級線程M if (m->p->runqhead != m->p->runqtail && runtime·atomicload(&runtime·sched.nmspinning) == 0 && runtime·atomicload(&runtime·sched.npidle) > 0) // TODO: fast atomic wakep(); // 執行goroutine execute(gp); }
Routine狀態遷移
前面說的是G,M是怎樣創建的以及什么時候創建、運行。那么goroutine在M是是怎樣進行調度的呢?這個才是goroutine的調度核心問題,即上面代碼中的schedule。在說調度之前,我們必須知道goroutine的狀態有什么,以及各個狀態之間的關系。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。