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.調度順序
下面說一下詳細的過程
5.1 協程調度
5.1.1 主動調度
主動的讓出CPU資源, 此時當前協程切換到g0, 取消G與M之間的綁定關系, 再將此G放入全局隊列中, 并調用schedule函數開始新一輪的循環
5.1.2 搶占式調度
當某個協程占用CPU時間過長時, go語言調度器就會強制中斷執行.并保存上下文等待下次調度
總結
以上是生活随笔為你收集整理的Go语言线程与协程之间的关系之GMP模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Go中线程和协程的区别
- 下一篇: Go语言垃圾回收(GC)