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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Go学习笔记—并发高级

發布時間:2023/12/10 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go学习笔记—并发高级 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Go并發機制

? 協程:一個線程可以對應多個協程,協程串行運行在用戶空間。協程運行在線程之上,當一個協程執行完成后,可以選擇主動讓出,讓另一個協程運行在當前線程之上。協程并沒有增加線程數量,只是在線程的基礎之上通過分時復用的方式運行多個協程,而且協程的切換在用戶態完成,切換的代價比線程從用戶態到內核態的代價小很多。

? Go摒棄線程、進程、協程,提出goroutine:

  • M(machine):一個M代表一個內核線程(與KSE一一對應)
  • P(processor):一個P代表執行一個Go代碼片段所必須的資源(上下文環境)
  • G(goroutine):一個G代表一個Go代碼片段。

? 一個M與一個P關聯之后,就形成一個G的運行環境(內核線程+上下文環境)。M與KSE一對一,M與P總是一對一(當一個M因系統調用阻塞(運行的G進入系統調用),此時P會與M分離開來,并與新建/空閑的M關聯),P與G一對多

操作作用
runtime/debug.SetMaxThreads設置M的最大數量
runtime.GOMAXPORCS設置P的最大數量(可運行G隊列的數量)

一、M、P、G

——M(Machine)

? 系統維護一個全局M列表(runtime.allm) 調度器維護一個空閑M列表(runtime.sched.midle)

——P(Processor)

? 系統維護一個全局P列表(runtime.allp) 調度器維護一個空閑P列表(runtime.sched.pidle)

? 每個P維護一個可運行G隊列(runtime.p.runq)(隊列滿則會分出一半給調度器可運行G隊列)與一個自由G列表(runtime.p.gfree)(已經運行完成的G,在欲啟用一個go語句時,會復用該列表中的G。當P中的自由G列表元素過多或過少時,調度器的自由G列表會與其進行轉移)

狀態說明
Pidle當前P未與任何M存在關聯
Prunning當前P正在與某個M關聯
Psyscall當前P中運行的那個G正在進行系統調用
Pgcstop運行時系統需要停止調度(系統開始垃圾回收的一些步驟,會將全部P設為此狀態)
Pdead當前P已經不會再被使用(調整最大P數量后,多余的P會被設為此狀態)


? 非dead狀態的P在系統欲停止調度時都會被置于Pgcstop狀態。等到需要重啟調度時,會被統一置于Pidle狀態,即公平的接受再次調度。同時進入dead狀態的P,其可運行的G與自由的G都會被轉移到調度器的可運行G列表與自由G列表中。

——G(goroutine例程)

? 系統維護一個全局G列表(runtime.allgs)

? 調度器維護一個可運行G列表(runtime.sched.runqhead runtime.sched.runqtail) 一個自由G列表(runtime.sched.gfreeStack runtime.sched.gfreeNoStack)

狀態說明
Gidle剛被新分配,還未初始化
Grunnable正在可運行隊列中等待運行
Grunning當前G正在運行
Gsyscall當前G正在執行系統調用
Gwaiting當前G正在阻塞
Gdead當前G正在閑置
Gcopystack當前G的棧正在被移動


? Gdead不同于Pdead,前者可以加入自由列表等待再次復用,后者只會被銷毀。

二、調度器

? Go調度器不是運行在某個專用內核線程中的程序,調度器會運行在幾乎所有已存在的M(內核線程)中。

? 調度器基本數據結構:空閑M列表,空閑P列表,可運行G隊列,自由G列表,此外還有幾個重要字段與需要停止調度的任務(Stop the world,STW)有關。

字段名數據類型作用
gcwaitinguint32是否需要因一些任務而停止調度(比如垃圾回收)
stopwaitint32需要停止但仍未停止的P數量
stopnotenote實現與stopwait相關的事件通知機制

? 在停止調度前,gcwaiting被置為1,調度任務在發現這一狀態后,將當前P狀態置為Pgcstop并將stopwait字段減一。當stopwait減為0時,說明所有P已置為Pgcstop,此時利用stopnote喚醒待執行的任務(比如垃圾回收),之后恢復gcwaiting為0。

字段名數據類型作用
sysmonwaitunit32在停止調度期間系統監控任務是否在等待
sysmonnotenote實現與sysmonwait相關的事件通知機制

? 這兩個字段針對系統監測任務,即在執行需要停止調度的任務之前,也需要停止系統監測任務。系統監測程序發現所有P都已經閑置或gcwaiting不為0,會將sysmonwait置為1,并使用sysmonnote暫停自身,結束后,再恢復這兩個狀態。

一輪調度

? 在啟動Go程序并完成初始化后,會啟動一輪調度使得封裝了main函數的G可以被調度運行,在G運行阻塞、結束、退出系統調用后都會引發一輪調度。

  • M與G的成對鎖定,是為了CGO準備。即C的函數庫會將數據存儲于內核線程,所以為了放止數據丟失,只能在一段時期內將G與特定M進行關聯。

  • 當調度器為某個M1尋找到可執行G,但是檢查到某個M2已經與該G鎖定,則會立刻停止調度并停止M2,并將G交由M2運行(實際上是把M1的P交由M2),M1則尋找其他可執行G。——這意味著M2在運行鎖定的G前,不會做其他事,即資源被浪費。

  • 全力查找可運行的G:若還未找到G,則調度器會停止該M,并在以后特定時刻喚醒重新查找。還未找到可運行G的M稱為自旋狀態

  • 啟用或停止M

    (1)調度器調度一個M會預先檢查其是否與某個G鎖定;如果有,則會調用stoplockedm解除當前M與P的關聯并將P轉手,并暫停當前M的執行。

    (2)調度器為M發現一個可運行的G,但是該G已經被其他M鎖定。會調用startlockedm將本地M的P轉手給鎖定的M,并暫停本地M的運行。放入空閑M列表。

    (3)調度器發現有STW任務時,會調用gcstopm停止當前M。即釋放本地P(置為Pgcstop)并調用stopm。

    (4)只有當有新工作,并且由空閑P時,調用startm才可以執行一個M。

    操作作用
    stopm()停止當前M的執行
    gcstopm()為STW任務讓路,停止當前M,執行完畢后會被喚醒
    stoplockedm()停止已與某個G鎖定的M的執行,直到這個G可運行
    startlockedm(gp *g)喚醒與gp鎖定的那個M
    startm(p *p, spining bool)喚醒或創建一個M去關聯P并開始執行
三、其他幾個要點

——g0、m0

? g0:系統中每個M擁有的特殊G。g0所擁有的內存稱為M的調度棧,對應于內核中線程的棧,即OS線程棧。用于執行調度、垃圾回收、棧管理等。

? gsignal:系統中每個M擁有的特殊G,用來處理信號。即信號棧

? m0:Go程序的第一個內核線程runtime.g0,用于執行引導程序。

——調度器鎖和原子操作

? 每個M都有可能執行調度任務,而這些任務可能會并發進行,所以需要在讀寫一些全局變量時進行調度器鎖保護。比如sched.stopwait(STW任務時記錄需要停止的M)、sched.nmidle(對空閑M計數)、對核心元素容器進行存取(runtime.allp, runtime.sched.runqhead)。

? 同時也采用原子操作保護一些變量。比如sched.spining(對自旋M計數)、sched.ngsys(對系統G計數)、切換G狀態。

——調整GC

? Go的GC基于CMS(Concurrent Mark-Sweep)算法。調度器會適時調度GC相關任務執行,系統監測任務也會在必要時強制執行。有三種執行模式:

  • gcBackgroundMode:并發執行垃圾收集和清掃。
  • gcForceMode:串行的執行垃圾收集(即執行時停止調度),并發的執行垃圾清掃。
  • gcForceBlockMode:串行的執行垃圾收集和清掃。

總結

以上是生活随笔為你收集整理的Go学习笔记—并发高级的全部內容,希望文章能夠幫你解決所遇到的問題。

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