Go channel close 后再读取会发生什么?
Go channel close 后再读取会发生什么?

Go channel close 后再读取会发生什么?

Tags
Go
Published
March 29, 2021
Author
 
Go channel close 后再读取会发生什么?
 
这可能是日常开发的时候不会仔细思考的问题,今天看到了感觉非常有趣、决定好好的研究一下。实践是检验真理的唯一标准。
 
ch := make(chan string, 10) ch <- "2333" ch <- "2333" str := <-ch fmt.Println("<-ch", str) close(ch) str = <-ch fmt.Println("<-ch", str) str = <-ch fmt.Println("<-ch", str)
 
输出
 
<-ch 2333 <-ch 2333 <-ch
 
我们可以看到channel在被关闭后是可以继续读取的。即使数据被全部读取完后,仍然会零值返回。这时候有人说了「channel读取不是有第二个参数返回吗?」会发生什么呢?让我们继续测试下。
 
ch := make(chan string, 10) ch <- "2333" ch <- "2333" str := <-ch fmt.Println("<-ch", str) close(ch) str, ok := <-ch fmt.Println("<-ch", str, "ok:", ok) str, ok = <-ch fmt.Println("<-ch", str, "ok:", ok) str, ok = <-ch fmt.Println("<-ch", str, "ok:", ok)
 
输出
 
<-ch 2333 <-ch 2333 ok: true <-ch ok: false <-ch ok: false
 
可以看到,即使通道关闭了,ok 变量仍然在channel有值返回的情况下返回true。所以并不能通过第二个变量来判断通道是否关闭。这个返回值只能用来判断通道内是否还有没有数据可以读取。
当然我们还可以通过range遍历通道。当channel被关闭后。range会自动结束并退出遍历。
 
ch := make(chan string, 10) ch <- "2333" ch <- "2333" str := <-ch fmt.Println("<-ch", str) close(ch) for str := range ch { fmt.Println("<-ch", str) } fmt.Println("finished")
 
输出
 
<-ch 2333 <-ch 2333 finished
 
特别要注意的是当我们使用range遍历通道的时候、当通道不再有数据写入后应当关闭通道。否则会造成死锁的情况。
 
fatal error: all goroutines are asleep - deadlock!
 
今天问题可以引申一个新的问题,当channel关闭到底做了哪些操作呢?什么时候才是真正的把channel关闭了呢?在我查找资料的时候看到了下面的文章。值得深入学习一下。可以让我们更好的理解channel。
 

延展阅读