国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Golang > 正文

Golang優雅關閉channel的方法示例

2020-04-01 19:01:45
字體:
來源:轉載
供稿:網友

前言

最近使用go開發后端服務,服務關閉需要保證golang/71577.html">channel中的數據都被讀取完,理由很簡單,在收到系統的中斷信號后,系統需要做收尾工作,保證channel的數據都要被處理掉,然后才可以關閉系統。但實現起來沒那么簡單,下面來一起看看詳細的介紹吧。

關于Go channel設計和規范的批評:

  • 在不能更改channel狀態的情況下,沒有簡單普遍的方式來檢查channel是否已經關閉了
  • 關閉已經關閉的channel會導致panic,所以在closer(關閉者)不知道channel是否已經關閉的情況下去關閉channel是很危險的
  • 發送值到已經關閉的channel會導致panic,所以如果sender(發送者)在不知道channel是否已經關閉的情況下去向channel發送值是很危險的

所以Golang 內建的 close 方法可以關閉 channel,如果往已經關閉的 channel 發送數據,則會報錯:panic: close of closed channel.

看如下代碼,在一段時間內,生產者可以不斷往 channel 寫入數據,消費者進行處理,一段時間后 channel 關閉了,這個時候如果還有數據往 channel 發送,程序就會報錯。

package main import ( "fmt" "sync" "time") func main() { jobs := make(chan int) var wg sync.WaitGroup go func() { time.Sleep(time.Second * 3) close(jobs) }() go func() { for i := 0; ; i++ { jobs <- i fmt.Println("produce:", i) } }() wg.Add(1) go func() { defer wg.Done() for i := range jobs { fmt.Println("consume:", i) } }() wg.Wait()}

多運行幾次出錯的概率會比較大:

produce: 33334consume: 33334consume: 33335produce: 33335produce: 33336consume: 33336consume: 33337produce: 33337produce: 33338consume: 33338consume: 33339produce: 33339produce: 33340consume: 33340panic: send on closed channel goroutine 19 [running]:panic(0x49b660, 0xc042410bb0)  C:/Go/src/runtime/panic.go:500 +0x1afmain.main.func2(0xc04203a180)  C:/Users/tanteng/Go/src/examples/channel_close.go:18 +0x6bcreated by main.main  C:/Users/tanteng/Go/src/examples/channel_close.go:21 +0xb8exit status 2

如何優雅關閉 channel

那么在往通道發數據前如何判斷通道是否關閉呢?

1._,ok := <- jobs

此時如果 channel 關閉,ok 值為 false,如果 channel 沒有關閉,則會漏掉一個 jobs

2.使用 select 方式

再創建一個 channel,叫做 timeout,如果超時往這個 channel 發送 true,在生產者發送數據給 jobs 的 channel,用 select 監聽 timeout,如果超時則關閉 jobs 的 channel.

完整代碼如下:

package main import ( "fmt" "sync" "time") func main() { jobs := make(chan int) timeout := make(chan bool) var wg sync.WaitGroup go func() { time.Sleep(time.Second * 3) timeout <- true }() go func() { for i := 0; ; i++ { select { case <-timeout: close(jobs) return  default: jobs <- i fmt.Println("produce:", i) } } }() wg.Add(1) go func() { defer wg.Done() for i := range jobs { fmt.Println("consume:", i) } }() wg.Wait()}

這樣就可以保證不會往已經關閉的 channel 中發送數據了。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 贵溪市| 麦盖提县| 波密县| 清徐县| 鸡泽县| 恩平市| 阳曲县| 巴塘县| 琼海市| 六枝特区| 庆城县| 湘潭市| 阿拉善左旗| 临夏市| 望城县| 旅游| 神农架林区| 合水县| 永昌县| 大庆市| 临城县| 宝清县| 镇远县| 平定县| 西畴县| 东台市| 上杭县| 神农架林区| 宜都市| 沙湾县| 青冈县| 柳州市| 寻甸| 鄂伦春自治旗| 济南市| 白城市| 林芝县| 舒城县| 昌吉市| 江口县| 乐平市|