亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

目錄
GMP是什麼
線程M與處理器P是如何協(xié)作的?
新建的協(xié)程該分配到哪?
首頁 後端開發(fā) Golang 深入淺析Go語言中要有GMP調(diào)度模型的原因

深入淺析Go語言中要有GMP調(diào)度模型的原因

Apr 14, 2023 pm 03:26 PM
go 後端

Go為什麼要有GMP調(diào)度模型?以下這篇文章跟大家介紹一下Go語言中要有GMP調(diào)度模型的原因,希望對大家有幫助!

深入淺析Go語言中要有GMP調(diào)度模型的原因

GMP調(diào)度模型是Go的精髓所在,它合理地解決了多執(zhí)行緒並發(fā)調(diào)度協(xié)程的效率問題。

GMP是什麼

首先得清楚,GMP各代指什麼東西。

  • G: Goroutine的縮寫,指協(xié)程,運行在執(zhí)行緒上。
  • M: Machine的縮寫,即thead,線程,循環(huán)的調(diào)度協(xié)程並執(zhí)行。
  • P: Processor的縮寫,指處理器,將協(xié)程儲存到本機佇列,並為執(zhí)行緒提供未休眠的可用的協(xié)程,
##執(zhí)行緒M各自持有一個處理器P,當要取得協(xié)程時優(yōu)先從P中獲取,於是GMP模型圖解如下:

深入淺析Go語言中要有GMP調(diào)度模型的原因

#大致流程是,執(zhí)行緒M從P的佇列中獲取協(xié)程,如果取得不到,就會從全域佇列去競爭鎖來取得。

處理器P

協(xié)程G和執(zhí)行緒M結(jié)構(gòu)在前幾篇已經(jīng)講解了,這裡解析一下處理器P。

作用

處理器P儲存一批協(xié)程,使得執(zhí)行緒M可以無鎖定的從中取得協(xié)程,而無需與其他執(zhí)行緒去競爭全域佇列中的協(xié)程,從而提高調(diào)度協(xié)程效率。

原始碼解析

p結(jié)構(gòu)體原始碼在

src\runtime\runtime2.go中,這裡展示部分重要欄位。

type p struct {
   ...
   m           muintptr   // back-link to associated m (nil if idle)
   // Queue of runnable goroutines. Accessed without lock.
   runqhead uint32
   runqtail uint32
   runq     [256]guintptr
   runnext guintptr
   ...
}

  • m為處理器p所屬的執(zhí)行緒
  • runq是儲存協(xié)程的佇列
  • runqhead,runqtail表示佇列的頭尾指標
  • runnext指向下一個可執(zhí)行的協(xié)程

深入淺析Go語言中要有GMP調(diào)度模型的原因

線程M與處理器P是如何協(xié)作的?

src\runtime\proc.go中,有一個schedule方法,這是執(zhí)行緒運行的第一個函數(shù)。這函數(shù)中,執(zhí)行緒需要取得到可運行的協(xié)程,程式碼如下:

func schedule() {    
    ...
    // 尋找一個可運行的協(xié)程
    gp, inheritTime, tryWakeP := findRunnable() 
    ...
}
func findRunnable() (gp *g, inheritTime, tryWakeP bool) {
    // 從本地隊列中獲取協(xié)程
    if gp, inheritTime := runqget(pp); gp != nil {
       return gp, inheritTime, false
    }

    // 本地隊列拿不到則從全局隊列中獲取協(xié)程
    if sched.runqsize != 0 {
       lock(&sched.lock)
       gp := globrunqget(pp, 0)
       unlock(&sched.lock)
       if gp != nil {
          return gp, false, false
       }
    }
}

從本地佇列中取得協(xié)程

func runqget(pp *p) (gp *g, inheritTime bool) {
   next := pp.runnext // 隊列中下一個可運行的協(xié)程
   if next != 0 && pp.runnext.cas(next, 0) {
      return next.ptr(), true
   }
   ...
}

那麼如果本地佇列和全域佇列中都沒有協(xié)程了怎麼辦呢,難道就讓線程這麼閒著?

這時候處理器P就會任務竊取,從其他執(zhí)行緒的本地佇列中竊取一些任務,美其名曰分擔其他執(zhí)行緒的壓力,也提高了自己執(zhí)行緒的使用率。

原始碼在

src\runtime\proc.go\stealWork中,感興趣可以看看。

新建的協(xié)程該分配到哪?

新建的協(xié)程該分配到本地還是全域佇列呢,得分情況:

    Go認為新協(xié)程的優(yōu)先權高,於是先找本地佇列放入,而且還插隊。
  • 本隊佇列滿了才放入全域佇列。
實際流程為:

    隨機尋找P
  1. 將新協(xié)程放入P的
  2. runnext中,意味著下一個就運行該協(xié)程,插隊了
  3. 若P的協(xié)程滿了,則放入全域佇列
原始碼在

src\runtime\proc.go \newproc函數(shù)中。

// Create a new g running fn.
// Put it on the queue of g's waiting to run.
// The compiler turns a go statement into a call to this.
func newproc(fn *funcval) {
   gp := getg()
   pc := getcallerpc()
   systemstack(func() {
      newg := newproc1(fn, gp, pc) // 創(chuàng)建新協(xié)程

      pp := getg().m.p.ptr()
      runqput(pp, newg, true) // 尋找本地隊列放入

      if mainStarted {
         wakep()
      }
   })
}

結(jié)語

本篇初步介紹了GMP調(diào)度模型,具體介紹了處理器P以及執(zhí)行緒M取得協(xié)程的方式。

處理器P解決了多執(zhí)行緒互斥取得協(xié)程的問題,提高調(diào)度協(xié)程的效率,但是不管協(xié)程在本地還是全域佇列,目前看來還只是順序執(zhí)行,那Go是如何實現(xiàn)協(xié)程異步並發(fā)執(zhí)行的呢?咱下一篇繼續(xù)分析(雖然沒什麼人看...)。

推薦學習:

Golang教學

以上是深入淺析Go語言中要有GMP調(diào)度模型的原因的詳細內(nèi)容。更多資訊請關注PHP中文網(wǎng)其他相關文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發(fā)現(xiàn)涉嫌抄襲或侵權的內(nèi)容,請聯(lián)絡admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Switch語句如何運行? Switch語句如何運行? Jul 30, 2025 am 05:11 AM

Go的switch語句默認不會貫穿執(zhí)行,匹配到第一個條件後自動退出。 1.switch以關鍵字開始並可帶一個值或不帶值;2.case按順序從上到下匹配,僅運行第一個匹配項;3.可通過逗號列出多個條件來匹配同一case;4.不需要手動添加break,但可用fallthrough強制貫穿;5.default用於未匹配到的情況,通常放最後。

如何從GO中築巢的循環(huán)中斷 如何從GO中築巢的循環(huán)中斷 Jul 29, 2025 am 01:58 AM

在Go中,要跳出嵌套循環(huán),應使用標籤化break語句或通過函數(shù)返回;1.使用標籤化break:將標籤置於外層循環(huán)前,如OuterLoop:for{...},在內(nèi)層循環(huán)中使用breakOuterLoop即可直接退出外層循環(huán);2.將嵌套循環(huán)放入函數(shù)中,滿足條件時用return提前返回,從而終止所有循環(huán);3.避免使用標誌變量或goto,前者冗長易錯,後者非推薦做法;正確做法是標籤必須位於循環(huán)之前而非之後,這是Go語言中跳出多層循環(huán)的慣用方式。

使用上下文軟件包進行取消和超時 使用上下文軟件包進行取消和超時 Jul 29, 2025 am 04:08 AM

USECONTEXTTOPROPAGATECELLATION ANDDEADEADLINESACROSSGOROUTINES,ENABLINGCOOPERATIVECELLATIONININHTTPSERVERS,背景任務,andChainedCalls.2.withContext.withContext.withCancel(),CreatseAcancellableBableBablebableBableBableBablebableContExtandAndCandExtandCallCallCancelLcancel()

建立表演者為第三方API的客戶 建立表演者為第三方API的客戶 Jul 30, 2025 am 01:09 AM

使用專用且配置合理的HTTP客戶端,設置超時和連接池以提升性能和資源利用率;2.實現(xiàn)帶指數(shù)退避和抖動的重試機制,僅對5xx、網(wǎng)絡錯誤和429狀態(tài)碼重試,並遵守Retry-After頭;3.對靜態(tài)數(shù)據(jù)如用戶信息使用緩存(如sync.Map或Redis),設置合理TTL,避免重複請求;4.使用信號量或rate.Limiter限制並發(fā)和請求速率,防止被限流或封禁;5.將API封裝為接口,便於測試、mock和添加日誌、追蹤等中間件;6.通過結(jié)構(gòu)化日誌和指標監(jiān)控請求時長、錯誤率、狀態(tài)碼和重試次數(shù),結(jié)合Op

如何在Go中正確複製切片 如何在Go中正確複製切片 Jul 30, 2025 am 01:28 AM

要正確複製Go中的切片,必須創(chuàng)建新的底層數(shù)組,而不是直接賦值;1.使用make和copy函數(shù):dst:=make([]T,len(src));copy(dst,src);2.使用append與nil切片:dst:=append([]T(nil),src...);這兩種方法都能實現(xiàn)元素級別的複制,避免共享底層數(shù)組,確保修改互不影響,而直接賦值dst=src會導致兩者引用同一數(shù)組,不屬於真正複製。

與時間和日期一起工作 與時間和日期一起工作 Jul 30, 2025 am 02:51 AM

Go使用time.Time結(jié)構(gòu)體處理日期和時間,1.格式化和解析使用參考時間“2006-01-0215:04:05”對應“MonJan215:04:05MST2006”,2.創(chuàng)建日期使用time.Date(year,month,day,hour,min,sec,nsec,loc)並指定時區(qū)如time.UTC,3.時區(qū)處理通過time.LoadLocation加載位置並用time.ParseInLocation解析帶時區(qū)的時間,4.時間運算使用Add、AddDate和Sub方法進行加減和計算間隔,

如何將template.parsefs與GO嵌入? 如何將template.parsefs與GO嵌入? Jul 30, 2025 am 12:35 AM

使用template.ParseFS與embed包可將HTML模板編譯進二進製文件。 1.導入embed包並用//go:embedtemplates/.html將模板文件嵌入embed.FS變量;2.調(diào)用template.Must(template.ParseFS(templateFS,"templates/.html"))解析所有匹配的模板文件;3.在HTTP處理器中通過tmpl.ExecuteTemplate(w,"home.html",nil)渲染指定

如何在GO中導入本地軟件包? 如何在GO中導入本地軟件包? Jul 30, 2025 am 04:47 AM

要正確導入本地包,需使用Go模塊並遵循目錄結(jié)構(gòu)與導入路徑匹配原則。 1.使用gomodinit初始化模塊,如gomodinitexample.com/myproject;2.將本地包放在子目錄中,如mypkg/utils.go,包聲明為packagemypkg;3.在main.go中通過完整模塊路徑導入,如import"example.com/myproject/mypkg";4.避免相對導入、路徑不匹配或命名衝突;5.對於模塊外的包可使用replace指令。只要確保模塊初始化

See all articles