亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

多個延遲與延遲匿名函數

多個延遲與延遲匿名函數

Go
慕姐8265434 2021-11-08 14:48:27
發出defer依賴于順序的多個語句,或者延遲打包邏輯的匿名函數是否更安全或更慣用?例子:defer os.Remove(tempFile.Name())defer tempFile.Close()在上述情況下,語法最少,但延遲的順序與要執行的邏輯相反。在下面的情況下,有更多行,更多“語法”,但邏輯順序更自然:defer func() {    tempFile.Close()    os.Remove(tempFile.Name())}()使用哪一種?
查看完整描述

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 通常是合適的。


查看完整回答
反對 回復 2021-11-08
?
海綿寶寶撒

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 處理程序結束時等待的緩慢工作時,使調用異步可以顯著改善用戶體驗。


查看完整回答
反對 回復 2021-11-08
  • 2 回答
  • 0 關注
  • 240 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號