defer學習指南

一、源頭:

早期管理資源(如數據庫連接、鎖、文件句柄、網絡連接)和狀態清理異常麻煩。
必須在每個可能的返回點(return、err、panic)手動重復清理代碼,極易遺漏且打斷主要邏輯思路!

像Java語言雖然用了Try-Catch,但缺點是邏輯不清晰、臃腫、不容易判斷錯誤出在什么地方。

作為新生代的Go,及眾多語言之精華,推出了defer處理機制。
尤其是在Go1.14版本時,性能開銷接近零,更無后顧之憂。

二、定義:

1、語法:

defer functionCall(..arguments..)

defer后面直接跟一個函數調用(可以是命名函數/匿名函數/方法...)

2、定義:

當函數執行到defer語句時(注冊時),他會立即求值此時該函數調用的參數并將此次函數調用(包括已求值的參數)放到一個延遲調用表中。這個調用函數與goroutine關聯,采用LIFO(后進先出的方式調用)。切記這個延遲調用表不會立即執行,而是會等到(函數真正結束之--函數(return或panic)之)在調用。

3、特性:

1、延遲執行:運行到defer時,只是將求值后的參數與調用的函數一并打包到延遲調用表中,需等到函數體結束之后在執行

2、LIFO方式執行:后進先出的方式執行

3、參數求值時機:defer 語句中的函數參數的值,是在執行到defer語句時(即注冊時)就確定并保存下來的,而不是在延遲函數實際執行時才求值。

4、作用域:自各函數體

三、應用:

1、臨近釋放:(邏輯清晰)

mu.Lock()
defer mu.Unlock() // 好習慣!確保解鎖
// ... 操作共享數據 ...

2、panic補獲:(防止程序崩潰)

特殊情況,根據源碼分析---協程中出現panic,若不能再該協程中捕獲,則會導致整個程序崩潰。

func test(){defer func(){if r := recover(); r!=nil{fmt.Println(r);}}()panic(1);
}

3、循環函數釋放:(利用完資源后,及時釋放資源)

// 正確做法:將文件處理封裝到函數,defer 在每次循環的匿名函數結束時執行
func outerFunc() {for _, filename := range filenames {func() { // 匿名函數f, err := os.Open(filename)if err != nil {log.Println(err)return // 退出匿名函數}defer f.Close() // 延遲到當前匿名函數結束時執行 (即本次循環結束)// ... 處理 f ...}() // 立即調用匿名函數}
}

4、查看執行順序:

代碼右上角,有個運行小按鈕,點擊運行查看。

package mainimport ("fmt""log"
)func g(i int) {if i > 1 {fmt.Println("Panicking!")panic(1)}defer fmt.Println("Defer in g", i)fmt.Println("Printing in g", i)g(i + 1)
}func f() {defer func() {if r := recover(); r != nil {log.Println("Recovered in f", r)}}()fmt.Println("Calling g.")g(0)fmt.Println("Returned normally from f.")
}func main() {f()
}

四、底層:

這個是我扒出來的底層源碼,重點了解heap、link這倆。

type _defer struct {heap      bool  	//表示是分配在堆上還是棧上。rangefunc bool    	// true for rangefunc listsp        uintptr 	// 棧指針pc        uintptr 	// 程序計數器fn        func()  	// 表示需要被延遲執行的函數。link      *_defer 	// 指向下一個 _defer 結構體的指針。// If rangefunc is true, *head is the head of the atomic linked list// during a range-over-func execution.head *atomic.Pointer[_defer]
}
  • defer 語句注冊時,會創建一個 _defer 結構體實例。

  • 多個 defer?通過 link 字段形成一個單鏈表(LIFO 棧),掛載到當前 goroutine 的結構上(g._defer)。新的 defer 總是插入鏈表頭部。

主要有兩大種分配方式。

1、堆棧分配

區別:分配位置的不同

獲取到runtime_defer結構體,它都會被追加到所在 Goroutine?_defer?鏈表的最前面。

2、開放編碼

不建額外結構,直接把 defer 代碼塞到函數退出前,用位掩碼控制執行,開銷幾乎和普通調用一樣。

3、選擇:

首先考慮開放編碼(已經優化到:實際消耗跟調用普通函數差不多的地步),后棧分配保底堆分配

以下是整理的Go版本迭代全史,有興趣的可以一看,挺有趣的。


📅?Go 版本迭代全史(2009–2025)

??早期階段

版本發布時間核心特性
初始開源2009-11-10正式開源,獲得 TIOBE 年度語言稱號
Go r562011-03-16首個穩定版本
Go 1.02012-03-28首個正式版本,承諾向后兼容性;引入?go tool pprofgo vet

🔄?每半年發布周期(2013 年起)

版本發布時間核心特性
Go 1.12013-05-13重寫調度器(支持 Work-Stealing 算法);引入競態檢測器
Go 1.22013-12-01支持全切片表達式;go test?支持覆蓋率統計
Go 1.32014-06-18棧模型改為連續棧;引入?sync.Pool
Go 1.42014-12-10支持 Android;運行時從 C 改為 Go;移除?src/pkg?層級
Go 1.52015-08-19自舉(移除 C 代碼);優化 GC(延遲降至 30ms);引入?vendor?機制
Go 1.62016-02-17默認支持 HTTP/2;GC 延遲進一步降低
Go 1.72016-08-15引入?context?包;SSA 后端優化(性能提升 5–35%)
Go 1.82017-02-17GC 延遲降至亞毫秒級;defer?性能提升 50%
Go 1.92017-08-24引入類型別名;新增并發安全的?sync.Map
Go 1.102018-02-16構建緩存(Build Cache)默認開啟
Go 1.112018-08-25引入 Go Modules;支持 WebAssembly
Go 1.122019-03-01優化 TLS 1.3 支持;改進模塊機制
Go 1.132019-09-03支持二進制/八進制字面量;錯誤處理增強(errors.Is/As/Unwrap
Go 1.142020-02-25接口允許方法集重疊;Goroutine 支持異步搶占調度;defer?性能接近零開銷
Go 1.152020-08-11優化鏈接器;改進內聯策略
Go 1.162021-02支持靜態文件嵌入;默認啟用 Go Modules

🚀?重大革新階段(2022–2025)

版本發布時間核心特性
Go 1.182022-03-15引入泛型;支持模糊測試(Fuzzing);工作區模式(Multi-Module Workspaces)
Go 1.232025 年初引入迭代器(seq/seq2);gopls?現代化工具鏈;go get?管理工具鏈
Go 1.242025 年中標準庫支持?strings/slices/maps?迭代器;增強 WebAssembly 安全性與性能
Go 1.252025-08 (預計)移除核心類型(Core Types);簡化泛型規范;優化錯誤提示

太多了不好記,有興趣查看時,可以重點看

1、初始開源-2009-11-10,go降生到了這個世界上

2、Go1.5 :2015,go開始用母語了,實現自舉(Go 編譯 Go),GC 延遲從 300ms 降至 30ms,奠定現代 Go 基礎

3、Go1.11:2018,引入了Go Module解決了依賴問題,讓現在的我都收益不止--今年2025

4、Go1.18:2022,泛型、模糊測試、工作區多模塊,等均進行了新功能的填充與優化。這個咱暫接觸不夠多,后期接觸了,會回來優化本篇博客

.....

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88815.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88815.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88815.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

NLP_知識圖譜_大模型——個人學習記錄

1. 自然語言處理、知識圖譜、對話系統三大技術研究與應用 https://github.com/lihanghang/NLP-Knowledge-Graph 深度學習-自然語言處理(NLP)-知識圖譜:知識圖譜構建流程【本體構建、知識抽取(實體抽取、 關系抽取、屬性抽取)、知識表示、知…

linux:進程詳解(1)

目錄 ?編輯 1.進程基本概念與基本操作 1.1 概念 1.2 描述進程-PCB 1.2.1PCB的基本概念 1.2.2 task_ struct 1.2.3 查看進程 2.進程狀態 2.1 Linux內核源碼展示 2.2 進程狀態查看 ?編輯 2.3 Z(zombie)-僵?進程 2.4 僵尸進程的危害 2.5 孤兒進程 3.進程優先級 …

碳中和目標下的全球產業鏈重構:深度解析與未來路徑

引言:氣候臨界點與產業鏈的系統性風險2023年,全球平均氣溫較工業化前上升1.2℃,南極冰蓋年消融量達1500億噸,極端天氣事件導致的經濟損失占全球GDP的2.3%。這一系列數據背后,暴露出傳統產業鏈的致命缺陷——其設計邏輯…

FPGA實現SDI轉LVDS視頻發送,基于GTX+OSERDES2原語架構,提供2套工程源碼和技術支持

目錄 1、前言工程概述免責聲明 2、相關方案推薦我已有的所有工程源碼總目錄----方便你快速找到自己喜歡的項目本博已有的 SDI 編解碼方案FPGA實現LVDS視頻收發方案 3、工程詳細設計方案工程設計原理框圖SDI 輸入設備Gv8601a 均衡器GTX 解串SMPTE SD/HD/3G SDI IP核BT1120轉RGB奇…

新手向:使用Python構建高效的日志處理系統

本文將詳細講解如何使用Python開發一個專業的日志分析工具,能夠自動化處理、分析和可視化各類日志文件,大幅提升運維效率。環境準備開發本工具需要以下環境配置:Python環境:建議Python 3.8或更高版本必要庫:pandas&…

大模型-量化技術

簡介 模型量化是一種重要的模型壓縮技術。其核心目標是在可控精度損失下,將大模型中浮點型權重(通常為 float32 等高精度格式)近似轉換為低精度離散值表示(通常為 int8)。 具體而言,該技術通過將模型的權重…

【C語言網絡編程】HTTP 客戶端請求(域名解析過程)

在做 C 語言網絡編程或模擬 HTTP 客戶端時,第一步就離不開“把域名解析為 IP 地址”這一步。很多人可能直接復制粘貼一段 gethostbyname 的代碼,但未必真正理解它的原理。 本篇博客將圍繞一個經典函數: char *host_to_ip(const char *hostna…

Node.js特訓專欄-實戰進階:16. RBAC權限模型設計

?? 歡迎來到 Node.js 實戰專欄!在這里,每一行代碼都是解鎖高性能應用的鑰匙,讓我們一起開啟 Node.js 的奇妙開發之旅! Node.js 特訓專欄主頁 專欄內容規劃詳情 我將從RBAC權限模型的基礎概念、核心組件講起,詳細闡述其設計原則、數據庫模型設計,還會結合代碼示例展示在…

mac上BRPC的CMakeLists.txt優化:解決Protobuf路徑問題

問題背景與挑戰 在構建高性能RPC框架BRPC時,?Protobuf依賴路徑的配置往往是開發者面臨的主要挑戰之一。原始CMake配置在尋找Protobuf庫時存在以下痛點: ?路徑搜索不精確?:默認find_library無法定位自定義安裝路徑下的Protobuf?版本兼容…

Go 性能分析利器:pprof 工具實戰指南

在 Go 語言開發中,性能問題往往是項目上線后最棘手的挑戰之一。無論是 CPU 占用過高、內存泄漏,還是 goroutine 失控,都可能導致服務響應緩慢甚至崩潰。而pprof作為 Go 官方提供的性能分析工具,就像一把精準的手術刀,能…

fio測試SSD直接I/O(Direct IO)性能僅有100MB/s的問題解決

針對您使用fio測試SSD直接I/O(Direct IO)性能僅有100MB/s的問題,結合SSD特性和fio測試原理 fio測試SSD直接I/O(Direct IO)性能僅有100MB/s的問題 - LinuxGuideLinuxGuide 以下是可能的原因及優化方案: &a…

EVO-0:具有隱空間理解的視覺-語言-動作模型

25年6月來自上海交大、EvoMind Tech 和上海算法創新研究院(IAAR-Shanghai)的論文“EVO-0: Vision-Language-Action Model with Implicit Spatial Understanding”。 視覺-語言-動作 (VLA) 模型已成為一種有前途的框架,可使通用機器人能夠在現…

文心大模型4.5開源測評:輕量化部署實踐與多維度能力驗證

前言:開源浪潮下的輕量化革命 2025年百度文心大模型4.5系列的開源,標志著國產大模型從“參數競賽”轉向“實用落地”的關鍵轉折。當行業仍在追逐千億參數模型時,文心4.5以0.3B輕量級模型撕開一條新賽道——單卡部署、低成本運維、中文場景高…

LeetCode 2401.最長優雅子數組

給你一個由 正 整數組成的數組 nums 。 如果 nums 的子數組中位于 不同 位置的每對元素按位 與(AND)運算的結果等于 0 ,則稱該子數組為 優雅 子數組。 返回 最長 的優雅子數組的長度。 子數組 是數組中的一個 連續 部分。 注意:長…

中華心法問答系統的解讀(1)

中華心法問答系統一、研究背景1. 研究意義2. 研究目的3. 信息檢索技術二、主要研究內容三、相關技術介紹1. Flask框架技術2. BERT模型(1)基本概念(2)BERT解決的問題(3)BERT的核心結構a. 模型結構b. 預訓練任…

Java 大視界 -- Java 大數據在智能安防視頻監控系統中的視頻摘要快速生成與檢索優化(345)

Java 大視界 -- Java 大數據在智能安防視頻監控系統中的視頻摘要快速生成與檢索優化(345)引言:正文:一、Java 構建的全場景視頻處理系統(含校園 / 工廠 / 礦區適配)1.1 校園宿舍區夜間檢索方案(…

信號量機制,互斥的避免自旋鎖的實現方法(操作系統)

這次的比喻場景要升級了,因為它既能解決互斥問題,也能解決同步問題。我們用一個更綜合的場景:一個擁有多輛共享單車的站點。共享單車 (資源):站點里有多輛共享單車,數量是有限的。你 (進程):想借一輛車去辦…

零基礎 “入坑” Java--- 十、繼承

文章目錄一、何為繼承二、繼承語法三、父類成員訪問1.成員變量2.成員方法四、super關鍵字五、子類構造方法六、super和this辨析七、再談初始化八、protected關鍵字九、繼承方式十、final關鍵字十一、繼承與組合根據我們學過的類的知識,我們來定義兩個類:…

JS進階-day1 作用域解構箭頭函數

作用域全局作用域——>盡量少使用,避免變量污染局部作用域——>函數作用域、塊級作用域作用域鏈——>底層變量查找機制(先在當前函數作用域查找,如果找不到,就沿著作用域鏈向上級作用域查找,直到全局作用域&a…

Arduino 無線通信實戰:使用 RadioHead實現 315MHz 433M模塊數據傳輸

本文將介紹如何使用 Arduino 和 RadioHead 庫實現 315MHz(或 433MHz)ASK 無線通信。通過兩個 Arduino 控制板,一個作為發射端,一個作為接收端,實現“按鍵控制 → 無線發送 → LED 控制”的基礎通信功能,非常…