关于channel的一些坑
channel可以分为无缓冲和带缓冲的通道
无缓冲的,必须要一个协程发送,一个协程接收
package main
func main() {
var ch = make(chan int)
ch <- 1
<- ch
}

在主协程main,执行到 ch <- 1,即发送完消息就阻塞了。
下一句 <- ch 永远无法执行,因为所有goroutines都睡着了(即没有协程接收) - 死锁!!!
上面的那段程序便是一个明显的错误样例。在main函数执行到ch <- 1的时候main(也是一个goroutine)便已挂起,而并没有其他goroutine负责接收消息,而下面一句 <-ch 永远无法执行,系统便自动判为timeout返回error。
这种所有线程或者进程都在等待资源释放的情况,我们便把它称之为死锁。
作者:Solonk8
链接:https://www.jianshu.com/p/147bd63801b6
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
假如是带缓冲的,如下
package main
func main() {
var ch = make(chan int, 1)
ch <- 1
<- ch
}
则不会报错,因为main goroutine并没有被阻塞,带缓冲1
如果连续发两个,则会报错,如下:
package main
func main() {
var ch = make(chan int, 1)
ch <- 1
ch <- 1
<- ch
}
但如果你及时接收了,则又不会报错,如下:
package main
func main() {
var ch = make(chan int, 1)
ch <- 1
<- ch
ch <- 1
<- ch
}
又或者在main goroutine里面再起一个goroutine,如下:
package main
func say(ch chan int) {
ch <- 1
}
func main() {
ch := make(chan int)
go say(ch) // 新起协程,main goroutine并没有被阻塞
<- ch
}
通道接收报错的情况:而且try-catch捕捉也无法避免crash
package main import ( "fmt" ) func recive(ch chan int) { defer func() { // 必须要先声明defer,否则不能捕获到panic异常 if err := recover(); err != nil { fmt.Println("error---------") } }() for { a := <-ch fmt.Println(a) } } func main() { ch := make(chan int, 1024) go recive(ch) done := make(chan struct{}) <-done }

对于无缓冲的信道来说,我们默认信道的发消息(send)和收消息(receive)都是阻塞(block)的。
换句话来说,无缓冲的信道在收消息和发消息的时候,goroutine都处于挂起状态。除非另一端准备好,否则goroutine无法继续往下执行。

浙公网安备 33010602011771号