2 回答

TA貢獻1866條經驗 獲得超5個贊
在此示例中,匿名函數更易于閱讀,尤其是在添加錯誤處理后。
f, err := ioutil.TempFile("", "prefix")
if err != nil {
log.Println("creating temp file:", err)
return
}
defer func() {
err := f.Close()
if err != nil {
log.Println("close:", err)
}
err = os.Remove(f.Name())
if err != nil {
log.Println("remove:", err)
}
}()
如果你有多個資源,那么多個defers 通常是合適的。

TA貢獻1809條經驗 獲得超8個贊
正如羅斯·萊特(Ross Light)的回答所說:
如果你有多個資源,那么多個 defer 通常是合適的。
2019 年 4 月:但在這種情況下,請考慮 Go 1.13(2019 年第四季度),因為它確實集成了go 問題 14939的修復程序:“運行時:延遲很慢”和go 問題 6980:“cmd/compile:在堆棧幀中分配一些延遲”
請參閱Go CL 171758:“cmd/compile,runtime:在堆棧上分配延遲記錄”
當 defer 在函數體中最多執行一次時,我們可以在堆棧上而不是在堆上為其分配 defer 記錄。
這應該會使像這樣的延遲(非常常見)更快。
此優化適用于 cmd/go 二進制文件中 370 個靜態延遲站點中的 363 個。
name old time/op new time/op delta
Defer-4 52.2ns ± 5% 36.2ns ± 3% -30.70% (p=0.000 n=10+10)
2019 年 10 月(幾周前發布了 Go 1.13)
這在CL 190098 中得到了證實 (Brad Fitzpatrick):
延期聲明的費用 [ go test -run NONE -bench BenchmarkDefer$ runtime]
With normal (stack-allocated) defers only: 35.4 ns/op
With open-coded defers: 5.6 ns/op
Cost of function call alone (remove defer keyword): 4.4 ns/op
但達米安·格里斯基補充道:
Defer 變得更便宜,但 panic/recover 更昂貴。
Cost of defer: 34ns -> 6ns.
Cost of panic/recover: 62ns -> 255ns
這不是一個糟糕的權衡。
換句話說,雖然使用多個 defer 可能是慣用的,但這種做法受到性能成本的阻礙,而 Go 1.13+ 不再關注性能成本。
(如Paschalis的博客文章“什么是延遲?你能跑多少? ”的說明)
如果延遲(在應該執行函數調用的地方,而不管代碼流如何),這將具有實際用途。
然而,John Refior指出,這defer是同步的:
實際上 defer 是在函數退出前立即執行的。
它是同步發生的,所以調用者等待 defer 完成。
因此,即使您現在可以有多個 defer,也要確保它們很快,或者,正如 John 所說:
幸運的是,將 goroutine 包裝在 a 中很容易defer,為我們提供了我們想要的流量控制和計時,而不會延遲調用者:
func Handler(w http.ResponseWriter, r *http.Request) {
log.Println("Entered Handler")
defer func() {
go func() {
time.Sleep(5 * time.Second)
log.Println("Exiting goroutine")
}()
log.Println("Exiting defer")
}()
}
defers 通常用于鎖定互斥鎖,或關閉連接或文件描述符,它們所做的工作很快,或者我們希望它在調用者繼續之前完成。
但是,當您執行客戶端不需要在 HTTP 處理程序結束時等待的緩慢工作時,使調用異步可以顯著改善用戶體驗。
- 2 回答
- 0 關注
- 240 瀏覽
添加回答
舉報