自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go語言中使用Defer幾個場景

開發(fā) 前端
在Go語言中, panic用于拋出異常, recover用于捕獲異常. recover只能在defer語句中使用, 直接調(diào)用recover是無效的.

關(guān)于 defer 的詳細(xì)介紹請參考: Defer, Panic, and Recover .

C++ 中模擬的 defer 實現(xiàn)請參考: C++版的defer語句

1. 簡化資源的回收

這是最常見的 defer 用法. 比如:

  1. mu.Lock()  
  2. defer mu.Unlock() 

當(dāng)然, defer 也有一定的開銷, 也有為了節(jié)省性能而回避使用的 defer 的:

  1. mu.Lock()  
  2. count++  
  3. mu.Unlock() 

從簡化資源的釋放角度看, defer 類似一個語法糖, 好像不是必須的.

2. panic異常的捕獲

defer 除了用于簡化資源的釋放外, 還是Go語言異??蚣艿囊粋€組成部分.

Go語言中, panic用于拋出異常, recover用于捕獲異常. recover只能在defer語句中使用, 直接調(diào)用recover是無效的.

比如:

  1. func main() {  
  2.     f()  
  3.     fmt.Println("Returned normally from f.")  
  4. }  
  5.  
  6. func f() {  
  7.     defer func() {  
  8.         if r := recover(); r != nil {  
  9.             fmt.Println("Recovered in f", r)  
  10.         }  
  11.     }()  
  12.     fmt.Println("Calling g.")  
  13.     g()  
  14.     fmt.Println("Returned normally from g.")  
  15. }  
  16.  
  17. func g() {  
  18.     panic("ERROR")  

因此, 如果要捕獲Go語言中函數(shù)的異常, 就離不開defer語句了.

3. 修改返回值

defer 除了用于配合 recover, 用于捕獲 panic 異常外, 還可以用于在 return 之后修改函數(shù)的返回值.

比如:

  1. func doubleSum(a, b int) (sum int) {  
  2.     defer func() {  
  3.         sum *= 2 
  4.     }()  
  5.     sum = a + b  

當(dāng)然, 這個特性應(yīng)該只是 defer 的副作用, 具體在什么場景使用就要由開發(fā)者自己決定了.

4. 安全的回收資源

前面第一點提到, defer 最常見的用法是簡化資源的回收. 而且, 從資源回收角度看, defer 只是一個語法糖.

其實, 也不完全是這樣, 特別是在涉及到第二點提到的panic異常等因素導(dǎo)致goroutine提前退出時.

比如, 有一個線程安全的slice修改函數(shù), 為了性能沒有使用defer語句:

  1. func set(mu *sync.Mutex, arr []int, i, v int) {  
  2.     mu.Lock()  
  3.     arr[i] = v  
  4.     mu.Unlock()  

但是, 如果 i >= len(arr)的話, runtime就會拋出切片越界的異常(這里只是舉例, 實際開發(fā)中不應(yīng)該出現(xiàn)切片越界異常). 這樣的話, mu.Unlock() 就沒有機會被執(zhí)行了.

如果用defer的話, 即使出現(xiàn)異常也能保證mu.Unlock()被調(diào)用:

  1. func set(mu *sync.Mutex, arr []int, i, v int) {  
  2.     mu.Lock()  
  3.     defer mu.Unlock()  
  4.     arr[i] = v  

當(dāng)然, Go語言約定異常不會跨越package邊界. 因此, 調(diào)用一般函數(shù)的時候不用擔(dān)心goroutine異常退出的情況.

不過對于一些比較特殊的package, 比如go test依賴的testing包, 包中的t.Fatal就是依賴了Go中類似異常的特性(準(zhǔn)確的說是調(diào)用了runtime.Goexit()).

比如有以下的測試函數(shù)(詳情請參考Issue5746):

  1. func TestFailed(t *testing.T) {  
  2.     var wg sync.WaitGroup  
  3.     for i := 0; i < 2; i++ {  
  4.         wg.Add(1)  
  5.         go func(id int) {  
  6.             // defer wg.Done()  
  7.             t.Fatalf("TestFailed: id = %v\n", id)  
  8.             wg.Done()  
  9.         }(i)  
  10.     }  
  11.     wg.Wait()  

當(dāng)測試失敗的時候, wg.Done()將沒有機會執(zhí)行, 最終導(dǎo)致wg.Wait()死鎖.

對于這個例子, 安全的做法是使用defer語句保證wg.Done()始終會被執(zhí)行.

原文鏈接:http://my.oschina.net/chai2010/blog/140065

責(zé)任編輯:林師授 來源: OSCHINA
相關(guān)推薦

2024-01-07 23:11:16

defer?Go語言

2021-06-07 23:19:44

Golang語言 Defer

2022-09-29 10:01:05

Go編程語言文本文件

2016-02-22 15:02:57

GoRedis連接池

2022-11-03 20:38:01

CMD命令Go

2011-05-25 13:22:05

PHPJSON

2024-04-01 00:02:56

Go語言代碼

2023-10-09 07:14:42

panicGo語言

2024-05-10 08:36:40

Go語言對象

2014-04-09 09:32:24

Go并發(fā)

2023-12-21 07:09:32

Go語言任務(wù)

2023-01-12 08:52:50

GoroutinesGo語言

2021-07-15 23:18:48

Go語言并發(fā)

2024-04-07 11:33:02

Go逃逸分析

2023-01-31 08:48:49

Go語言文件

2024-08-19 01:10:00

RedisGo代碼

2021-04-23 07:59:17

Godefer 鏈表

2022-07-19 12:25:29

Go

2023-07-29 15:03:29

2023-11-30 08:09:02

Go語言
點贊
收藏

51CTO技術(shù)棧公眾號