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

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

 更新時(shí)間: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的使用和底層實(shí)現(xiàn),需要的朋友可以參考下

1:defer是什么

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

1.1 資源釋放

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

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

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

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

1.2 捕獲異常

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

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

2:defer語法

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

defer demoFunc(args)

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

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 語句并不是原子級(jí)的,實(shí)際的執(zhí)行過程為為設(shè)置返回值—>ret指令,defer 語句是在返回前執(zhí)行,所以返回過程是:「設(shè)置返回值—>執(zhí)行defer—>ret」

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

要了解defer的實(shí)現(xiàn),先看下defer的底層數(shù)據(jù)結(jié)構(gòu)和各個(gè)參數(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 計(jì)數(shù)器值,棧指針
   pc        uintptr  // pc 計(jì)數(shù)器值,程序計(jì)數(shù)器
   fn        *funcval // defer 傳入的函數(shù)地址,也就是延后執(zhí)行的函數(shù)
   _panic    *_panic  // defer 的 panic 結(jié)構(gòu)體
   link      *_defer  // 同一個(gè)協(xié)程里面的defer 延遲函數(shù),會(huì)通過該指針連接在一起
}

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

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

為啥是逆序執(zhí)行

defer結(jié)構(gòu)有個(gè)link指針,是指向的一個(gè)defer單鏈表的頭,每次咱們聲明一個(gè)defer的時(shí)候,就會(huì)將該defer的數(shù)據(jù)插入到這個(gè)單鏈表頭部的位置,取defer進(jìn)行執(zhí)行的時(shí)候,是從單鏈表的頭開始去取的,這就是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) //新建一個(gè)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聲明的時(shí)候已經(jīng)確定了

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Golang報(bào)“import cycle not allowed”錯(cuò)誤的2種解決方法

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

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

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

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

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

最新評(píng)論