Go學(xué)習(xí)記錄之runtime包深入解析
前言:
先前學(xué)習(xí)到goroutine協(xié)程與channel調(diào)節(jié)并發(fā)同步時(shí),有涉及到關(guān)于runtime包管理goroutine運(yùn)行時(shí)的知識(shí)點(diǎn)。由于沒(méi)有接觸過(guò),并且出于goroutine的重要性(runtime聽(tīng)著很高大上)的原因,通過(guò)多方學(xué)習(xí)并博客記錄。
一、runtime包內(nèi)容學(xué)習(xí)
1、作用:
其作用主要是與程序的運(yùn)行時(shí)環(huán)境進(jìn)行交互,提供了一系列函數(shù)和變量,用于控制、管理和監(jiān)視程序的執(zhí)行:
① Goroutine和并發(fā)控制:
runtime包提供了一些函數(shù)來(lái)管理goroutine,如創(chuàng)建和銷毀goroutine、設(shè)置最大可同時(shí)執(zhí)行的CPU數(shù)目等,以及用于并發(fā)控制的函數(shù),如讓出CPU時(shí)間片、鎖定和解鎖goroutine到線程等。
package main import ( "fmt" "runtime" "time" ) func worker() { defer fmt.Println("Worker exiting") runtime.Gosched() // 主動(dòng)讓出 CPU fmt.Println("Worker running") } func main() { go worker() time.Sleep(time.Second) fmt.Println("Number of goroutines:", runtime.NumGoroutine()) }
② 垃圾回收:
Go語(yǔ)言使用自動(dòng)垃圾回收機(jī)制來(lái)管理內(nèi)存,runtime包提供了手動(dòng)觸發(fā)垃圾回收、設(shè)置垃圾回收的百分比、獲取內(nèi)存統(tǒng)計(jì)信息等函數(shù),用于對(duì)垃圾回收進(jìn)行調(diào)控和監(jiān)測(cè)。
func main() { var m runtime.MemStats runtime.ReadMemStats(&m) fmt.Printf("Allocated memory: %d bytes\n", m.Alloc) runtime.GC() // 手動(dòng)觸發(fā) GC runtime.ReadMemStats(&m) fmt.Printf("After GC: %d bytes\n", m.Alloc) }
③ 棧和堆操作:
runtime包提供了函數(shù)來(lái)獲取當(dāng)前goroutine的堆棧信息、完整的堆棧跟蹤,以及對(duì)堆棧進(jìn)行分析和剖析的相關(guān)函數(shù)。
④ 系統(tǒng)信息和調(diào)試:
runtime包提供了獲取CPU核心數(shù)、CPU性能分析、調(diào)試信息等函數(shù),可以用于獲取關(guān)于系統(tǒng)的一些基本信息和進(jìn)行程序的調(diào)試。
⑤ 錯(cuò)誤處理:
runtime包提供了獲取調(diào)用棧信息、根據(jù)PC地址獲取函數(shù)信息等函數(shù),用于錯(cuò)誤處理和調(diào)試時(shí)追蹤錯(cuò)誤發(fā)生的位置。
func printStack() { var buf [4096]byte n := runtime.Stack(buf[:], false) fmt.Printf("Stack trace:\n%s\n", string(buf[:n])) } func main() { defer printStack() panic("Something went wrong!") }
⑥ P操作:
runtime包提供了與處理器(P)的相關(guān)操作,如獲取可同時(shí)執(zhí)行的最大P數(shù)目、綁定goroutine到特定的P等。
⑦ 信號(hào)處理:
runtime包提供了處理C語(yǔ)言信號(hào)的函數(shù),用于和外部C庫(kù)進(jìn)行交互時(shí)的信號(hào)處理。
通過(guò)使用runtime包提供的函數(shù)和變量,可以更控制程序的運(yùn)行時(shí)行為、優(yōu)化性能、處理錯(cuò)誤和調(diào)試問(wèn)題。但需要注意,對(duì)runtime包過(guò)度依賴可能會(huì)降低代碼的可移植性
2、相關(guān)函數(shù):
runtime包提供了與程序運(yùn)行時(shí)環(huán)境交互的函數(shù)和變量,包含了與上述作用相關(guān)的函數(shù):
① Goroutine相關(guān):
goexit():終止當(dāng)前goroutine的執(zhí)行。
GOMAXPROCS(n int):設(shè)置可同時(shí)執(zhí)行的最大CPU數(shù)。
NumGoroutine():返回當(dāng)前存在的goroutine數(shù)目。
② 垃圾回收:
GC(): 手動(dòng)觸發(fā)垃圾回收。
SetFinalizer(obj interface{}, finalizer interface{}):為對(duì)象設(shè)置一個(gè)垃圾回收的終結(jié)器(finalizer),當(dāng)對(duì)象被垃圾回收時(shí),終結(jié)器會(huì)被調(diào)用。
③ 棧:
Stack(buf []byte, all bool): 返回當(dāng)前goroutine的堆棧信息。
StackTrace(p *Profiling)::返回當(dāng)前程序的完整堆棧跟蹤。
④ 內(nèi)存統(tǒng)計(jì):
ReadMemStats(m *MemStats): 獲取當(dāng)前程序的內(nèi)存使用統(tǒng)計(jì)信息。
⑤ 并發(fā)控制:
LockOSThread(): 鎖定當(dāng)前goroutine到當(dāng)前線程上。
UnlockOSThread(): 解除當(dāng)前goroutine對(duì)當(dāng)前線程的鎖定。(等)
同樣的,由于其對(duì)底層進(jìn)行交互,過(guò)多使用相關(guān)函數(shù)也會(huì)降低可移植性,開(kāi)發(fā)過(guò)程中需要注意。
3、幾個(gè)較為重要的函數(shù):
① runtime.Gosched():讓出CPU時(shí)間片,重新等待安排任務(wù)
package main import ( "fmt" "runtime" ) func main() { go func(s string) { for i := 0; i < 2; i++ { fmt.Println(s) } }("world") // 主協(xié)程 for i := 0; i < 2; i++ { // 切一下,再次分配任務(wù) runtime.Gosched() fmt.Println("hello") } }
② runtime.Goexit():退出當(dāng)前協(xié)程
package main import ( "fmt" "runtime" ) func main() { go func() { defer fmt.Println("A.defer") func() { defer fmt.Println("B.defer") // 結(jié)束協(xié)程 runtime.Goexit() defer fmt.Println("C.defer") fmt.Println("B") }() fmt.Println("A") }() for { } }
③ runtime.GOMAXPROCS:
Go運(yùn)行時(shí)的調(diào)度器使用GOMAXPROCS參數(shù)來(lái)確定需要使用多少個(gè)OS線程來(lái)同時(shí)執(zhí)行Go代碼。默認(rèn)值是機(jī)器上的CPU核心數(shù)。例如在一個(gè)8核心的機(jī)器上,調(diào)度器會(huì)把Go代碼同時(shí)調(diào)度到8個(gè)OS線程上(GOMAXPROCS是m:n調(diào)度中的n)。
Go語(yǔ)言中可以通過(guò)runtime.GOMAXPROCS()函數(shù)設(shè)置當(dāng)前程序并發(fā)時(shí)占用的CPU邏輯核心數(shù)。
Go1.5版本之前,默認(rèn)使用的是單核心執(zhí)行。Go1.5版本之后,默認(rèn)使用全部的CPU邏輯核心數(shù)。
可以通過(guò)將任務(wù)分配到不同的CPU邏輯核心上實(shí)現(xiàn)并行的效果
func a() { for i := 1; i < 10; i++ { fmt.Println("A:", i) } } func b() { for i := 1; i < 10; i++ { fmt.Println("B:", i) } } func main() { runtime.GOMAXPROCS(1) go a() go b() time.Sleep(time.Second) }
兩個(gè)任務(wù)只有一個(gè)邏輯核心,此時(shí)是做完一個(gè)任務(wù)再做另一個(gè)任務(wù)。 將邏輯核心數(shù)設(shè)為2,此時(shí)兩個(gè)任務(wù)并行執(zhí)行,代碼如下。
func a() { for i := 1; i < 10; i++ { fmt.Println("A:", i) } } func b() { for i := 1; i < 10; i++ { fmt.Println("B:", i) } } func main() { runtime.GOMAXPROCS(2) go a() go b() time.Sleep(time.Second) }
二、底層設(shè)計(jì):
Go語(yǔ)言的高效與簡(jiǎn)潔,離不開(kāi)其運(yùn)行時(shí)環(huán)境。runtime包作為Go語(yǔ)言運(yùn)行時(shí)系統(tǒng)的核心接口,承載著內(nèi)存管理、協(xié)程調(diào)度、垃圾回收、類型信息處理等關(guān)鍵功能。深入理解runtime包的底層設(shè)計(jì),可以深入了解Go語(yǔ)言的運(yùn)行機(jī)制。
1、內(nèi)存管理與垃圾回收的底層協(xié)作
① 內(nèi)存分配策略
runtime包中的內(nèi)存分配器采用分層設(shè)計(jì),分為線程緩存(Thread Cache)、中心緩存(Central Cache)和堆(Heap)三個(gè)層級(jí):
• 線程緩存:每個(gè)Go線程擁有獨(dú)立的線程緩存,用于快速分配小對(duì)象(通常小于16字節(jié)),避免頻繁訪問(wèn)全局資源,減少鎖競(jìng)爭(zhēng);
• 中心緩存:作為線程緩存的補(bǔ)充,負(fù)責(zé)從堆中獲取大塊內(nèi)存,并切割成適合線程緩存的小塊,平衡各線程間的內(nèi)存使用;
• 堆:內(nèi)存分配的最終來(lái)源,由垃圾回收器統(tǒng)一管理,當(dāng)線程緩存和中心緩存無(wú)法滿足需求時(shí),直接從堆中分配內(nèi)存 。
② 垃圾回收協(xié)同工作
垃圾回收器(GC)與內(nèi)存分配器緊密配合,runtime包通過(guò)一系列函數(shù)控制GC的行為,如runtime.GC()可手動(dòng)觸發(fā)垃圾回收。在GC過(guò)程中:
• 標(biāo)記階段:從根對(duì)象(如全局變量、棧上變量)出發(fā),標(biāo)記所有可達(dá)對(duì)象;
• 清除階段:回收未被標(biāo)記的對(duì)象,將其占用的內(nèi)存歸還到空閑列表;
• 整理階段(可選):在特定情況下,對(duì)堆內(nèi)存進(jìn)行整理,減少內(nèi)存碎片 。
2、協(xié)程調(diào)度的底層實(shí)現(xiàn)細(xì)節(jié)
runtime包是協(xié)程調(diào)度的核心執(zhí)行者,基于M:N調(diào)度模型實(shí)現(xiàn)高效的協(xié)程調(diào)度:
• Goroutine(G):用戶態(tài)的輕量級(jí)線程,是Go語(yǔ)言并發(fā)的基本單元;
• Machine(M):對(duì)應(yīng)操作系統(tǒng)線程,負(fù)責(zé)執(zhí)行Goroutine中的代碼;
• Processor(P):協(xié)程調(diào)度的關(guān)鍵組件,維護(hù)本地協(xié)程隊(duì)列,綁定到M上以減少上下文切換開(kāi)銷。
調(diào)度過(guò)程中,runtime包通過(guò)以下機(jī)制確保協(xié)程高效運(yùn)行:
• 本地隊(duì)列優(yōu)先:P優(yōu)先從本地隊(duì)列獲取Goroutine執(zhí)行,減少競(jìng)爭(zhēng);
• 工作竊取算法:當(dāng)本地隊(duì)列為空時(shí),P從其他P的本地隊(duì)列竊取Goroutine,均衡負(fù)載;
• 阻塞處理:當(dāng)M執(zhí)行的Goroutine發(fā)生阻塞(如I/O操作),M與P分離,P綁定到其他空閑M繼續(xù)執(zhí)行其他Goroutine,避免線程浪費(fèi) 。
3、運(yùn)行時(shí)類型信息與反射支持
runtime包管理著程序中所有類型的元數(shù)據(jù),這些信息是反射功能的基礎(chǔ):
• 類型描述:通過(guò)結(jié)構(gòu)體記錄類型的大小、對(duì)齊方式、方法集合等信息,如rtype結(jié)構(gòu)體存儲(chǔ)類型的基本屬性,itab結(jié)構(gòu)體記錄接口類型與具體實(shí)現(xiàn)類型的映射關(guān)系;
• 反射實(shí)現(xiàn):reflect包依賴runtime包提供的類型信息,在運(yùn)行時(shí)動(dòng)態(tài)獲取對(duì)象的類型、調(diào)用方法、修改屬性 。
例如,在進(jìn)行反射操作時(shí),runtime包負(fù)責(zé)提供類型比較、方法查找等底層支持,確保反射操作的正確性和高效性。
4、runtime包與開(kāi)發(fā)者實(shí)踐
雖然runtime包的大部分功能在幕后自動(dòng)運(yùn)行,但開(kāi)發(fā)者在某些場(chǎng)景下仍需關(guān)注其行為:
• 性能調(diào)優(yōu):通過(guò)runtime.GOMAXPROCS()設(shè)置處理器數(shù)量,優(yōu)化協(xié)程調(diào)度效率;利用runtime/pprof包進(jìn)行性能分析,定位內(nèi)存泄漏、CPU瓶頸等問(wèn)題;
• 特殊場(chǎng)景處理:在需要與操作系統(tǒng)深度交互時(shí),使用runtime包提供的系統(tǒng)調(diào)用接口;在編寫高性能程序時(shí),通過(guò)runtime包的內(nèi)存分配函數(shù)手動(dòng)管理內(nèi)存 。
總結(jié)
到此這篇關(guān)于Go學(xué)習(xí)記錄之runtime包深入解析的文章就介紹到這了,更多相關(guān)Go runtime包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang命令行進(jìn)行debug調(diào)試操作
今天小編就為大家分享一篇關(guān)于,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-04-04golang開(kāi)發(fā)微框架Gin的安裝測(cè)試及簡(jiǎn)介
這篇文章主要為大家介紹了golang微框架Gin的安裝測(cè)試及簡(jiǎn)介,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2021-11-11基于golang的簡(jiǎn)單分布式延時(shí)隊(duì)列服務(wù)的實(shí)現(xiàn)
這篇文章主要介紹了基于golang的簡(jiǎn)單分布式延時(shí)隊(duì)列服務(wù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02Go 1.21新增的slices包中切片函數(shù)用法詳解
Go 1.21新增的 slices 包提供了很多和切片相關(guān)的函數(shù),可以用于任何類型的切片,本文通過(guò)代碼示例為大家介紹了部分切片函數(shù)的具體用法,感興趣的小伙伴可以了解一下2023-08-08golang 如何獲取pem格式RSA公私鑰長(zhǎng)度
這篇文章主要介紹了golang 如何獲取pem格式RSA公私鑰長(zhǎng)度操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12Golang基于epoll實(shí)現(xiàn)最簡(jiǎn)單網(wǎng)絡(luò)通信框架
這篇文章主要為大家詳細(xì)介紹了Golang如何基于epoll實(shí)現(xiàn)最簡(jiǎn)單網(wǎng)絡(luò)通信框架,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)學(xué)習(xí)2023-06-06golang實(shí)踐-第三方包為私有庫(kù)的配置方案
這篇文章主要介紹了golang實(shí)踐-第三方包為私有庫(kù)的配置方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-05-05golang?cache帶索引超時(shí)緩存庫(kù)實(shí)戰(zhàn)示例
這篇文章主要為大家介紹了golang?cache帶索引超時(shí)緩存庫(kù)實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09