golang defer效能損耗和實際使用場景

2021-09-29 02:27:07 字數 2185 閱讀 7098

我們常常聽到別人說:」defer 在棧退出時執行,會有效能損耗,盡量不要用。「 前面的部落格 defer原理 我們分析了defer延遲呼叫的底層實現原理 。下面我們就基於那篇原理分析文章,來分析一下 defer 延遲呼叫的效能損耗。

package main

import

("sync"

"testing"

)var lock sync.mutex

func

nodefer()

func

defer()

func

benchmarknodefer

(b *testing.b)

}func

benchmarkdefer

(b *testing.b)

}

benchmark的執行結果如下:

ytlou@ytlou-mac  ~/desktop/golang/golang_study/study/basic/defer   master ●✚  go test -bench=. defer_latency_test.go

goos: darwin

goarch: amd64

benchmarknodefer-12 90020019 11.3 ns/op

benchmarkdefer-12 37018846 33.0 ns/op

pass

ok command-line-arguments 2.294s

我們19款16g記憶體mac上測試,結果顯示使用defer後的函式開銷確實比沒使用高了不少,這損耗用到**去了呢?

我們回憶一下 defer原理 中對於defer延遲呼叫編譯成彙編之後的彙編**,defer 關鍵字其實涉及了一系列的連鎖呼叫,內部 runtime 函式的呼叫就至少多了三步,分別是 runtime.deferproc 一次和 runtime.deferreturn 兩次。

而這還只是在執行時的顯式動作,另外編譯器做的事也不少,例如:

這一些動作途中還要涉及最小單元 _defer 的獲取/建立(在堆或棧), defer 和 recover 鍊錶的邏輯處理和消耗等動作。

defer 很多使用場景都是資源的close, 確保資源能夠在函式棧呼叫結束的時候釋放資源。比如下面的例子:

()但是一定得這麼寫嗎?其實並不,很多人給出的理由都是 「怕你忘記」 這種說辭,這沒有毛病。但需要認清場景,假設我的應用場景如下:

60)嗯,乙個請求當然沒問題,流量、併發一下子大了呢,那可能就是個災難了。你想想為什麼?併發高的時候,持有成千上萬的 http response物件,但是又沒有及時的釋放掉,而是使用 defer延遲釋放,導致併發高的時候造成很嚴重的效能問題。

從常見的 defer + close 的使用組合來講,用之前建議先看清楚應用場景,在保證無異常的情況下確保盡早關閉才是首選。如果只是小範圍呼叫很快就返回的話,偷個懶直接一套組合拳出去也未嘗不可。

乙個 defer 關鍵字實際上包含了不少的動作和處理,和你單純呼叫乙個函式一條指令是沒法比的。而與對照物相比,它確確實實是有效能損耗,目前延遲呼叫的全部開銷大約在 30ns,但 defer 所提供的作用遠遠大於此,你從全域性來看,它的損耗非常小,並且官方還不斷地在優化中。

因此,對於 「go defer 會有效能損耗,盡量不能用?」 這個問題,我認為該用就用,應該及時關閉就不要延遲,使用時一定要想清楚場景。

還有一點:defer使用最重要的不是效能問題,defer 最大的功能是 panic 後依然有效。如果沒有 defer,panic 後就會導致 unlock 丟失,從而導致死鎖了。 我覺得這個case非常經典。

裝箱與拆箱效能損耗詳解

拆箱是將引用型別轉換為值型別 反之,裝箱 利用裝箱和拆箱功能,可通過允許值型別的任何值與object 型別的值相互轉換,將值型別與引用型別鏈結起來 例如 int val 100 object obj val console.writeline 物件的值 obj 這是乙個裝箱的過程,是將值型別轉換為引...

Golang defer 使用時的坑

defer是golang語言中的關鍵字,用於資源的釋放,會在函式返回之前進行呼叫。一般採用如下模式 f,err os.open filename if err nil defer f.close 如果有多個defer表示式,呼叫順序類似於棧,越後面的defer表示式越先被呼叫。不過如果對defer的...

golang defer使用 資源關閉時候多用

go語言中有種不錯的設計,即延遲 defer 語句,你可以在函式中新增多個defer語句。當函式執行到最後時,這些defer語句會按照逆序執行,最後該函式返回。特別是當你在進行一些開啟資源的操作時,遇到錯誤需要提前返回,在返回前你需要關閉相應的資源,不然很容易造成資源洩露等問題。如下 所示,我們一般...