成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go語言中使用Defer幾個場景

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

關于 defer 的詳細介紹請參考: Defer, Panic, and Recover .

C++ 中模擬的 defer 實現請參考: C++版的defer語句

1. 簡化資源的回收

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

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

當然, defer 也有一定的開銷, 也有為了節省性能而回避使用的 defer 的:

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

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

2. panic異常的捕獲

defer 除了用于簡化資源的釋放外, 還是Go語言異常框架的一個組成部分.

Go語言中, panic用于拋出異常, recover用于捕獲異常. recover只能在defer語句中使用, 直接調用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語言中函數的異常, 就離不開defer語句了.

3. 修改返回值

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

比如:

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

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

4. 安全的回收資源

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

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

比如, 有一個線程安全的slice修改函數, 為了性能沒有使用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就會拋出切片越界的異常(這里只是舉例, 實際開發中不應該出現切片越界異常). 這樣的話, mu.Unlock() 就沒有機會被執行了.

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

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

當然, Go語言約定異常不會跨越package邊界. 因此, 調用一般函數的時候不用擔心goroutine異常退出的情況.

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

比如有以下的測試函數(詳情請參考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()  

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

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

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

責任編輯:林師授 來源: OSCHINA
相關推薦

2024-01-07 23:11:16

defer?Go語言

2021-06-07 23:19:44

Golang語言 Defer

2022-09-29 10:01:05

Go編程語言文本文件

2022-11-03 20:38:01

CMD命令Go

2016-02-22 15:02:57

GoRedis連接池

2011-05-25 13:22:05

PHPJSON

2024-04-01 00:02:56

Go語言代碼

2024-05-10 08:36:40

Go語言對象

2023-10-09 07:14:42

panicGo語言

2014-04-09 09:32:24

Go并發

2024-04-07 11:33:02

Go逃逸分析

2021-07-15 23:18:48

Go語言并發

2023-12-21 07:09:32

Go語言任務

2023-01-12 08:52:50

GoroutinesGo語言

2023-01-30 15:41:10

Channel控制并發

2023-11-30 08:09:02

Go語言

2022-07-19 12:25:29

Go

2021-06-08 07:45:44

Go語言優化

2023-07-29 15:03:29

2024-08-19 01:10:00

RedisGo代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲精品乱码久久久久久久久久 | 一级二级三级黄色 | 亚洲一区二区高清 | 美女艹b | 欧美亚洲高清 | 久久精品色欧美aⅴ一区二区 | 国产综合精品 | 99re6在线| 亚洲第一女人av | 亚洲在线免费 | 欧美成人精品激情在线观看 | 一区二区视频在线观看 | 91文字幕巨乱亚洲香蕉 | 欧美一级久久 | 国产超碰人人爽人人做人人爱 | 黑人巨大精品欧美一区二区免费 | 国产二区在线播放 | 黄瓜av | 久久在视频 | 天天综合永久入口 | 欧美一级免费看 | 久久久久久www | 欧美男人亚洲天堂 | 国产在线视频在线观看 | 夜夜爽99久久国产综合精品女不卡 | 久久av一区二区三区 | 免费黄色在线 | 天堂av中文 | 中文字幕日韩欧美一区二区三区 | 91视频一区二区 | 久久久国产一区二区三区四区小说 | 久久精品无码一区二区三区 | 成人在线免费网站 | 久久久日韩精品一区二区三区 | 亚洲一级视频在线 | 日韩欧美中文字幕在线观看 | 亚洲一区二区三区久久 | 久久夜视频 | 亚洲精品自在在线观看 | 精品三级在线观看 | 久色|