欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解go語言是如何實現(xiàn)協(xié)程的

 更新時間:2024年04月19日 09:36:13   作者:shark_chili  
go語言的精華就在于協(xié)程的設(shè)計,只有理解協(xié)程的設(shè)計思想和工作機制,才能確保我們能夠完全的利用協(xié)程編寫強大的并發(fā)程序,所以本文將給大家介紹了go語言是如何實現(xiàn)協(xié)程的,文中有詳細的代碼講解,需要的朋友可以參考下

寫在文章開頭

go語言的精華就在于協(xié)程的設(shè)計,只有理解協(xié)程的設(shè)計思想和工作機制,才能確保我們能夠完全的利用協(xié)程編寫強大的并發(fā)程序。

詳解協(xié)程工作機制和實現(xiàn)

協(xié)程示例

正式介紹底層之前,我們給出一段協(xié)程的代碼示例,可以看到筆者開啟一個協(xié)程進行函數(shù)內(nèi)部調(diào)用:

func foo1() {
 fmt.Println("foo1 調(diào)用 foo2")
 foo2()
}

func foo2() {
 fmt.Println("foo2調(diào)用foo3")
 foo3()
}

func foo3() {
 fmt.Println("foo3 執(zhí)行了")
}

func main() {
 //設(shè)置WaitGroup等待協(xié)程結(jié)束
 var wg sync.WaitGroup
 wg.Add(1)

 go func() {
  foo1()
  defer wg.Done()
 }()

 //等待上述協(xié)程運行結(jié)束
 wg.Wait()
}

運行結(jié)果如下:

foo1 調(diào)用 foo2
foo2調(diào)用foo3
foo3 執(zhí)行了

結(jié)合debug我們可以看到當前協(xié)程的調(diào)用棧幀,在函數(shù)調(diào)用前插入一個goexit的東西,結(jié)合這一點我們開始對協(xié)程的深入剖析:

在這里插入圖片描述

協(xié)程實現(xiàn)結(jié)構(gòu)

go語言的協(xié)程結(jié)構(gòu)為:

  • 通過一個stack記錄其高地址和低地址。
  • 通過schedsp(即stackpointer)棧幀的指針程序計數(shù)器pc(指向下一條運行的指令).
  • 采用goid生成唯一標識。
  • 然后再用atomicstatus記錄其執(zhí)行狀態(tài)。

基于這幾點我們結(jié)合上述的代碼給出協(xié)程的底層結(jié)構(gòu),如下圖所示,當前協(xié)程的stack記錄整個foo1函數(shù)的高低地址,假設(shè)我們當前的協(xié)程go來到foo2函數(shù)準備調(diào)用foo3函數(shù),我們的sched中的sp即stackpointer記錄foo2的指針,同時因為foo2內(nèi)部會調(diào)用foo3所以程序計數(shù)器pc記錄著調(diào)用foo3的指令。

最后因為協(xié)程都是由線程調(diào)度的,所以協(xié)程的內(nèi)部也有一個變量記錄著當前線程的指針m:

到此我們了解了協(xié)程核心結(jié)構(gòu),同時我們也在runtime2.go這一文件中即給出上述所說的核心變量:

type g struct {
 //記錄棧幀的高地址和低地址
 stack       stack   // offset known to runtime/cgo
 //......
 m         *m //執(zhí)行當前協(xié)程的線程指針
 //記錄當前堆棧的指針以及下一條指令的運行地址
 sched     gobuf
 atomicstatus atomic.Uint32
 goid         uint64
 
 //......
}

步入stack可以看到lohi兩個專門記錄棧幀高低地址的指針:

type stack struct {
 lo uintptr
 hi uintptr
}

對應(yīng)的我們也給出sched 的類型gobuf,可以看到sppc兩個核心指針變量:

type gobuf struct {
 
 sp   uintptr
 pc   uintptr
 //......
}

談?wù)刧o語言對于線程的抽象

上文我們提出線程的用m指針記錄,如下源碼所示,我們都知道在go語言中每個線程都會從一個協(xié)程隊列中獲取協(xié)程執(zhí)行,所以執(zhí)行時它會用curg記錄當前運行的協(xié)程,然后通過id對自己進行唯一標識,而mOS則是及記錄當前操作系統(tǒng)信息,這其中最核心的就是g0它就是每一個線程的操作調(diào)度器:

type m struct {
 g0      *g     // goroutine with scheduling stack
 id            int64 
 
 curg          *g       // current running goroutine
 
 mOS

}

了解整體結(jié)構(gòu)之后我們再來聊聊go語言線程的g0棧是如何工作的,如下圖所示,每一個g0棧都會通過schedule開始工作:

  • 通過execute從協(xié)程隊列中獲取任務(wù)。
  • 調(diào)用gogo方法在協(xié)程調(diào)用前插入go exit指針它記錄g0棧幀,這個指針就是用于協(xié)程執(zhí)行退出或者掛起是可以通過這個指針跳回g0棧。
  • 然后就是執(zhí)行當前協(xié)程。
  • 協(xié)程執(zhí)行完成切換回g0棧,重新調(diào)用schedule方法再次從步驟1開始執(zhí)行,由此構(gòu)成一個循環(huán)。

這里我們也給出asm_amd64.s中關(guān)于gogo的匯編代碼,可以看到gobuf_sp方法它會記錄當前stack pointer也就是我們上文針對g0所說的g0棧地址:

TEXT gogo<>(SB), NOSPLIT, $0
 get_tls(CX)
 MOVQ DX, g(CX)
 MOVQ DX, R14  // set the g register
 //記錄g0棧地址
 MOVQ gobuf_sp(BX), SP // restore SP
 MOVQ gobuf_ret(BX), AX
 MOVQ gobuf_ctxt(BX), DX
 MOVQ gobuf_bp(BX), BP
 MOVQ $0, gobuf_sp(BX) // clear to help garbage collector
 MOVQ $0, gobuf_ret(BX)
 MOVQ $0, gobuf_ctxt(BX)
 MOVQ $0, gobuf_bp(BX)
 MOVQ gobuf_pc(BX), BX
 JMP BX

小結(jié)

自此我們從go語言底層實現(xiàn)的角度完整的剖析的協(xié)程與線程的關(guān)系和實現(xiàn),希望對你有幫助。

以上就是詳解go語言是如何實現(xiàn)協(xié)程的的詳細內(nèi)容,更多關(guān)于go實現(xiàn)協(xié)程的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用Golang打印特定的日期時間的操作

    使用Golang打印特定的日期時間的操作

    這篇文章主要給大家詳細介紹了如何使用Golang打印特定的日期時間的操作,文中有詳細的代碼示例,具有一定的參考價值,需要的朋友可以參考下
    2023-07-07
  • 一文帶你掌握Golang基礎(chǔ)之通道

    一文帶你掌握Golang基礎(chǔ)之通道

    在Java中,多線程之間的通信方式有哪些?記得嗎?Java多線程間通信的解決方案有很多種,比如:synchronized。在go中,就一種:通道,文中介紹的非常詳細,感興趣的同學(xué)可以參考下
    2023-05-05
  • golang?中?recover()的使用方法

    golang?中?recover()的使用方法

    這篇文章主要介紹了Guam與golang??recover()的使用方法,Recover?是一個Go語言的內(nèi)建函數(shù),可以讓進入宕機流程中的?goroutine?恢復(fù)過來,下文更多相關(guān)資料需要的小伙伴可以參考一下
    2022-04-04
  • golang語言中wasm 環(huán)境搭建的過程詳解

    golang語言中wasm 環(huán)境搭建的過程詳解

    將 golang 打包為 WASM,通常有兩種打包方式,一種是 golang 自帶的,另外是使用 tinygo ,接下來通過本文給大家介紹golang語言中wasm 環(huán)境搭建的過程,感興趣的朋友一起看看吧
    2021-11-11
  • 基于Go語言簡單實現(xiàn)事件管理器

    基于Go語言簡單實現(xiàn)事件管理器

    在編程中,事件管理器是一種常見的工具,用于通過通知來觸發(fā)操作,本文將介紹一個簡單的Go事件管理器的實現(xiàn),并通過異步改進提高其性能,感興趣的可以了解下
    2023-11-11
  • Go語言中Timer計時器的使用技巧詳解

    Go語言中Timer計時器的使用技巧詳解

    Go語言中的time包里有個Timer計時器的功能,這篇文章主要就是來和大家介紹一下Timer計時器的使用技巧,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-07-07
  • go實現(xiàn)冒泡排序的示例代碼

    go實現(xiàn)冒泡排序的示例代碼

    這篇文章主要介紹了go實現(xiàn)冒泡排序的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 利用Go語言搭建WebSocket服務(wù)端方法示例

    利用Go語言搭建WebSocket服務(wù)端方法示例

    這篇文章主要給大家介紹了利用Go語言搭建WebSocket服務(wù)端方法,文中通過示例代碼介紹的非常詳細,需要的朋友們可以參考借鑒,下面來一起看看吧。
    2017-04-04
  • Go語言面試題之select和channel的用法

    Go語言面試題之select和channel的用法

    金九銀十面試季到了(PS:貌似今年一年都是面試季),就業(yè)環(huán)境很差,導(dǎo)致從業(yè)人員不得不卷。本文將重點講解一下Go面試進階知識點之select和channel,需要的可以參考一下
    2022-09-09
  • 淺談beego默認處理靜態(tài)文件性能低下的問題

    淺談beego默認處理靜態(tài)文件性能低下的問題

    下面小編就為大家?guī)硪黄獪\談beego默認處理靜態(tài)文件性能低下的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06

最新評論