日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Go语言线程与协程之间的关系之GMP模型

發布時間:2025/3/21 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go语言线程与协程之间的关系之GMP模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. GMP模型

這里首先給出GMP模型的調度策略. 讓大家有一個全局的認識更好

2. G (groutine)

G就是goroutine的意思, 代表了一個協程. 每次go調用的時候,都會創建一個G對象,它包括棧、指令指針以及對于調用goroutines很重要的其它信息,比如阻塞它的任何channel,其主要數據結構:

type g struct {stack stack // 描述了真實的棧內存,包括上下界............. // 中間還有很多部分m *m // 當前G的綁定的msched gobuf // goroutine切換時,用于保存g的上下文 param unsafe.Pointer // 用于傳遞參數,睡眠時其他goroutine可以設置param,喚醒時該goroutine可以獲取atomicstatus uint32stackLock uint32 goid int64 // goroutine的IDwaitsince int64 // g被阻塞的大體時間lockedm *m // G被鎖定只在這個m上運行............. // 省略 }

看這個結構我們可以得知, G需要與M進行綁定. 當然最重要的還是sched這個結構體 存儲了調度時g的上下文(context)

type gobuf struct {// 保存CPU的rsp寄存器的值sp uintptr// 保存CPU的rip寄存器的值pc uintptr// 記錄這個gobuf對象屬于那個gg guintptrctxt unsafe.Pointerret sys.Uintreglr uintptrbp uintptr // for framepointer-enabled architectures }

sp, pc 寄存器的值, 棧指針等等. 記錄了上下文

3. M(machine)

M代表了一個線程 . 每次創建一個M的時候,都會有一個底層線程創建;所有的G任務,最終還是依附于M上執行,其主要數據結構:

type m struct {g0 *g // 帶有調度棧的goroutinegsignal *g // 處理信號的goroutinetls [6]uintptr // thread-local storagemstartfn func()curg *g // 當前運行的goroutinecaughtsig guintptr p puintptr // 關聯的p和執行的go代碼nextp puintptrid int32mallocing int32 // 狀態spinning bool // m是否out of workblocked bool // m是否被阻塞inwb bool // m是否在執行寫屏蔽 }

其中重點要關注的是 g0 和 curg , curg代表的當前執行的groutine協程

另一個是g0,是帶有調度棧的goroutine,這是一個比較特殊的goroutine。普通的goroutine的棧是在堆上分配的可增長的棧,而g0的棧是M對應的線程的棧。所有調度相關的代碼,會先切換到該goroutine的棧中再執行。也就是說線程的棧也是用的g實現,而不是使用的OS的。

4. P(processor)

執行器或者處理器. 相當于一個管理者. 每一個M必須要綁定一個P. P自身有一個局部本地隊列用來保存g. 并且所有的p都共享這一個全局隊列

P負責調度goroutine,維護一個本地goroutine隊列,M從P上獲得goroutine并執行,同時還負責部分內存的管理。

下面的p的局部實現

lock mutexid int32status uint32 // 狀態,可以為pidle/prunning/...link puintptrschedtick uint32 // 每調度一次加1syscalltick uint32 // 每一次系統調用加1sysmontick sysmontick m muintptr // 關聯的mmcache *mcacheracectx uintptrgoidcache uint64 // goroutine的ID的緩存goidcacheend uint64runqhead uint32 // 頭部runqtail uint32 // 尾部// 隊列在這呢runq [256]guintptr // 可運行的goroutine的隊列runnext guintptr // 下一個運行的g }

5.調度順序


下面說一下詳細的過程

  • go func(){}創建一個新的goroutine
  • 這個goroutine會被挑選進入一個P的本地隊列, 若是本地隊列滿了, 那么就進入全局的隊列
  • 這時M向P要goroutine去執行了. G依附于M上運行,每個M綁定一個P。如果P的本地隊列沒有G,M會從全局隊列尋找G, 如果全局隊列也沒有G, 那么P會從其他P里面竊取G
  • M被操作系統調度到CPU上面執行, G也就執行了, 若是在此期間,M這個線程遇到阻塞或者系統調用, 那么此時P就會與M解綁. 并在M的休眠隊列里面喚醒一個新的M與之綁定, 然后再去運行G.
  • 若是在此期間是G發生了阻塞, 那么M也會阻塞. 此時M就會與P解綁, 由M1接管P.去運行其他的G. M等待阻塞的返回, 就將G放入全局隊列中了, 自己就去休眠了.
  • 運行完之后G就會被銷毀退出.
  • 5.1 協程調度

    5.1.1 主動調度

    主動的讓出CPU資源, 此時當前協程切換到g0, 取消G與M之間的綁定關系, 再將此G放入全局隊列中, 并調用schedule函數開始新一輪的循環

    5.1.2 搶占式調度

    當某個協程占用CPU時間過長時, go語言調度器就會強制中斷執行.并保存上下文等待下次調度

    總結

    以上是生活随笔為你收集整理的Go语言线程与协程之间的关系之GMP模型的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。