欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go關(guān)鍵字defer的使用和底層實現(xiàn)

 更新時間:2023年11月23日 09:05:17   作者:小許code  
defer是Go語言的關(guān)鍵字,一般用于資源的釋放和異常的捕捉,defer語句后將其后面跟隨的語句進(jìn)行延遲處理,就是說在函數(shù)執(zhí)行完畢后再執(zhí)行調(diào)用,也就是return的ret指令之前,本文給大家介紹了Go關(guān)鍵字defer的使用和底層實現(xiàn),需要的朋友可以參考下

1:defer是什么

defer是Go語言的關(guān)鍵字,一般用于資源的釋放和異常的捕捉(比如:文件打開、加鎖、數(shù)據(jù)庫連接、異常捕獲),defer語句后將其后面跟隨的語句進(jìn)行延遲處理,就是說在函數(shù)執(zhí)行完畢后再執(zhí)行調(diào)用,也就是return的ret指令之前。

1.1 資源釋放

資源的釋放在代碼中有很多場景,比如打開文件描述符資源后,需要進(jìn)行file.close得到釋放,在打開文件后就加上defer,避免在后續(xù)因為err導(dǎo)致的return退出忘記釋放,文件資源。

func openFile() {
	file, err := os.Open("txt")
	if err != nil {
		return
	}
	defer file.Close() //合理位置
}

常見的加鎖場景,業(yè)務(wù)代碼中忘記釋放鎖,那么會導(dǎo)致資源得不到釋放,造成死鎖,但是defer就很好解決了這個問題,不管業(yè)務(wù)邏輯怎么處理,最終還是會釋放鎖。

func lockScene() {
	 var mutex sync.Mutex
	 mutex.Lock()
	 defer  mutex.Unlock()
	 //業(yè)務(wù)代碼...
}

1.2 捕獲異常

Go 語言中 recover 關(guān)鍵字主要用于捕獲異常,讓程序回到正常狀態(tài)。recover 可以中止 panic 造成的程序崩潰。它是一個只能在 defer 中發(fā)揮作用的函數(shù),在其他作用域中調(diào)用不會發(fā)揮作用

func demo()  {
 defer func() {
  if err := recover(); err !=nil{
   fmt.Println(string(Stack()))
  }
 }()
 panic("unknown")
}

2:defer語法

defer語法相對簡單,直接在普通函數(shù)之前加一個defer關(guān)鍵字

defer demoFunc(args)

雖然defer語法簡單,但是當(dāng)有多個defer注冊時,會以逆序執(zhí)行(類似棧:先進(jìn)后出),舉個栗子。

func f1() {
	defer fmt.Println("defer1")
	defer fmt.Println("defer2")
	fmt.Println("start")
	fmt.Println("end")
	return
}

這段代碼的字符串輸出結(jié)果是:start、end、defer2、defer1。首先輸出的defer字符串在正常的start、end后輸出可以很好理解(defer在函數(shù)返回前執(zhí)行),字符串defer2在defer1前輸出(逆序執(zhí)行)。

3:defer與return

Go語言中函數(shù)的 return 語句并不是原子級的,實際的執(zhí)行過程為為設(shè)置返回值—>ret指令,defer 語句是在返回前執(zhí)行,所以返回過程是:「設(shè)置返回值—>執(zhí)行defer—>ret」

4:defer底層實現(xiàn)

要了解defer的實現(xiàn),先看下defer的底層數(shù)據(jù)結(jié)構(gòu)和各個參數(shù)表示的意義(src/runtime/runtime2.go)

type _defer struct {
   siz     int32    // 參數(shù)和返回值的內(nèi)存大小
   started bool
   heap    bool       //是否分配在堆上面
   openDefer bool     // 是否經(jīng)過開放編碼優(yōu)化
   sp        uintptr  // sp 計數(shù)器值,棧指針
   pc        uintptr  // pc 計數(shù)器值,程序計數(shù)器
   fn        *funcval // defer 傳入的函數(shù)地址,也就是延后執(zhí)行的函數(shù)
   _panic    *_panic  // defer 的 panic 結(jié)構(gòu)體
   link      *_defer  // 同一個協(xié)程里面的defer 延遲函數(shù),會通過該指針連接在一起
}

defer怎么實現(xiàn)延遲的

通過資料了解到,defer在代碼中的位置在編譯后會有兩部分內(nèi)容: 1:deferproc負(fù)責(zé)把要執(zhí)行的函數(shù)保存起來,我們稱之為defer注冊 2:deferreturn是在defer注冊完成(deferproc)后,程序執(zhí)行后續(xù)業(yè)務(wù)代碼,直到通過deferreturn執(zhí)行注冊的defer函數(shù)

為啥是逆序執(zhí)行

defer結(jié)構(gòu)有個link指針,是指向的一個defer單鏈表的頭,每次咱們聲明一個defer的時候,就會將該defer的數(shù)據(jù)插入到這個單鏈表頭部的位置,取defer進(jìn)行執(zhí)行的時候,是從單鏈表的頭開始去取的,這就是defer先進(jìn)后出的原因。 底層代碼在src/runtime/panic.go,核心代碼做了說明

func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
	gp := getg() //獲取goroutine結(jié)構(gòu)
	if gp.m.curg != gp {
		// go code on the system stack can't defer
		throw("defer on system stack")
	}
	...
	d := newdefer(siz) //新建一個defer結(jié)構(gòu)
	if d._panic != nil {
		throw("deferproc: d.panic != nil after newdefer")
	}
	d.link = gp._defer // 新建defer的link指針指向g的defer
	gp._defer = d      // 新建defer放到g的defer位置,完成插入鏈表表頭操作
	d.fn = fn
	d.pc = callerpc
	d.sp = sp
	...
}

如圖:先聲明defer fun1()、再聲明 defer fun2(),fun2()在單鏈表鏈表頭部。

總結(jié)

1:defer關(guān)鍵字后面必須是函數(shù),也叫延遲函數(shù)

2:defer是逆序執(zhí)行(后進(jìn)先出),延遲函數(shù)中的參數(shù)在defer聲明的時候已經(jīng)確定了

3:在函數(shù)return之前執(zhí)行延遲函數(shù)

到此這篇關(guān)于Go關(guān)鍵字defer的使用和底層實現(xiàn)的文章就介紹到這了,更多相關(guān)Go defer使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • GO項目實戰(zhàn)之Gorm格式化時間字段實現(xiàn)

    GO項目實戰(zhàn)之Gorm格式化時間字段實現(xiàn)

    GORM自帶的time.Time類型JSON默認(rèn)輸出RFC3339Nano格式的,下面這篇文章主要給大家介紹了關(guān)于GO項目實戰(zhàn)之Gorm格式化時間字段實現(xiàn)的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • Gin+Gorm實現(xiàn)增刪改查的示例代碼

    Gin+Gorm實現(xiàn)增刪改查的示例代碼

    本文介紹了如何使用Gin和Gorm框架實現(xiàn)一個簡單的增刪改查(CRUD)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • 深入理解Go gin框架中Context的Request和Writer對象

    深入理解Go gin框架中Context的Request和Writer對象

    這篇文章主要為大家詳細(xì)介紹了Go語言的gin框架中Context的Request和Writer對象,文中的示例代碼講解詳細(xì),對我們深入了解Go語言有一定的幫助,快跟隨小編一起學(xué)習(xí)一下吧
    2023-04-04
  • golang中的defer函數(shù)理解

    golang中的defer函數(shù)理解

    defer是Go語言中的延遲執(zhí)行語句,用來添加函數(shù)結(jié)束時執(zhí)行的代碼,常用于釋放某些已分配的資源、關(guān)閉數(shù)據(jù)庫連接、斷開socket連接、解鎖一個加鎖的資源,這篇文章主要介紹了golang中的defer函數(shù)理解,需要的朋友可以參考下
    2022-10-10
  • go語言生成隨機(jī)數(shù)和隨機(jī)字符串的實現(xiàn)方法

    go語言生成隨機(jī)數(shù)和隨機(jī)字符串的實現(xiàn)方法

    隨機(jī)數(shù)在很多時候都可以用到,尤其是登錄時,本文就詳細(xì)的介紹一下go語言生成隨機(jī)數(shù)和隨機(jī)字符串的實現(xiàn)方法,具有一定的參考價值,感興趣的可以了解一下
    2021-12-12
  • Go語言單元測試超詳細(xì)解析

    Go語言單元測試超詳細(xì)解析

    本文介紹了了Go語言單元測試超詳細(xì)解析,測試函數(shù)分為函數(shù)的基本測試、函數(shù)的組測試、函數(shù)的子測試,進(jìn)行基準(zhǔn)測試時往往是對函數(shù)的算法進(jìn)行測驗,有時后一個算法在測試數(shù)據(jù)的基量不同時測試出的效果會不同我們需要對不同數(shù)量級的樣本進(jìn)行測試,下文需要的朋友可以參考下
    2022-02-02
  • Golang 高效排序數(shù)據(jù)詳情

    Golang 高效排序數(shù)據(jù)詳情

    本文我們介紹了怎么使用 Golang 語言標(biāo)準(zhǔn)庫 sort 包排序數(shù)據(jù),需要注意的是,除了本文使用的類型之外,其它任意類型只要實現(xiàn) sort.Interface 的三個方法,都可以調(diào)用 sort.Sort() 函數(shù)排序數(shù)據(jù)。
    2021-11-11
  • Golang報“import cycle not allowed”錯誤的2種解決方法

    Golang報“import cycle not allowed”錯誤的2種解決方法

    這篇文章主要給大家介紹了關(guān)于Golang報"import cycle not allowed"錯誤的2種解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以們下面隨著小編來一起看看吧
    2018-08-08
  • Go如何實現(xiàn)Websocket服務(wù)以及代理

    Go如何實現(xiàn)Websocket服務(wù)以及代理

    這篇文章主要介紹了Go如何實現(xiàn)Websocket服務(wù)以及代理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Go語言指針使用分析與講解

    Go語言指針使用分析與講解

    這篇文章主要介紹了Go語言指針使用分析與講解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07

最新評論