日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Go 知识点(11) — goroutine 泄露、设置子协程退出条件

發布時間:2023/11/28 生活经验 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go 知识点(11) — goroutine 泄露、设置子协程退出条件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 問題現象

如果在開發過程中不考慮 goroutine 在什么時候能退出和控制 goroutine 生命期,就會造成 goroutine 失控或者泄露的情況 ,看示例代碼:

func consumer(ch chan int) {for {data := <-chfmt.Println(data)}
}func main() {ch := make(chan int)for {var input string// 獲取輸入,模擬進程持續運行fmt.Scan(&input)go consumer(ch)// 輸出現在的goroutine數量fmt.Println("goroutines 個數為:", runtime.NumGoroutine())}}

運行程序,每輸入一個字符串+回車,將會創建一個 goroutine, 結果如下 :

a
goroutines 個數為: 2
b
goroutines 個數為: 3
c
goroutines 個數為: 4
d
goroutines 個數為: 5
e
goroutines 個數為: 6
f
goroutines 個數為: 7
g
goroutines 個數為: 8
h
goroutines 個數為: 9
i
goroutines 個數為: 10

上面代碼模擬一個進程根據需要創建 goroutine 的情況 。我們發現, 隨著輸入的字符串越來越多, goroutine 將會無限制地被創建,但并不會結束,因為 consumer 是個阻塞操作,且 channel 中沒有讓其退出的操作。如果一直持續下去將會造成內存大量分配,最終使進程崩潰。

那要如何解決呢?

2. 解決方案

2.1 創建單個子協程,在子協程中處理業務

修改上面代碼,將創建子協程的代碼挪動到循環外面。

func consumer(ch chan int) {for {data := <-chfmt.Println("data is: ", data)}
}func main() {ch := make(chan int)go consumer(ch) // 在循環外面創建協程for {var input stringfmt.Scan(&input)fmt.Println("goroutines 個數為:", runtime.NumGoroutine())}}

這樣輸出結果為:

a
goroutines 個數為: 2
v
goroutines 個數為: 2
x
goroutines 個數為: 2
w
goroutines 個數為: 2
f
goroutines 個數為: 2
g
goroutines 個數為: 2
b
goroutines 個數為: 2

從結果可以看到協程數量并沒有隨著收入字符的增多而增加,但是存在一個問題就是,子協程并沒有退出的機制。

如何解決呢?接著往下看

2.2 設置子協程退出條件

在主協程中設置當輸入字符串為 quit 時,往通道里面寫入 -1,子協程從通道里面獲取數據為 -1 時就退出。此時主協程仍然是有效的,但是子協程會永遠退出,所以協程數量為 1 。

func consumer(ch chan int) {for {data := <-ch// 收到的數據為 -1 時,退出該循環,同時也會退出該協程if data == -1 {break}fmt.Println("data is: ", data)}}func main() {ch := make(chan int)go consumer(ch) // 在循環外面創建協程for {var input stringfmt.Scan(&input)if input == "quit" {ch <- -1 // 當輸入為 quit 時,往通道里面寫入 -1}// 輸出現在的goroutine數量fmt.Println("goroutines 個數為:", runtime.NumGoroutine())}
}

輸出結果:

a
goroutines 個數為: 2
b
goroutines 個數為: 2
c
goroutines 個數為: 2
d
goroutines 個數為: 2
quit
goroutines 個數為: 2
a
goroutines 個數為: 1
b
goroutines 個數為: 1

3. 總結

從上面示例我們可以總結使用協程的一般原則:

  1. 盡量避免無限制的創建協程;
  2. 在需要反復創建協程的場景下,協程一定要有退出的條件,并且確保該退出條件能滿足(即代碼能執行到);

總結

以上是生活随笔為你收集整理的Go 知识点(11) — goroutine 泄露、设置子协程退出条件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。