无缓冲channel与容量为1的channel的区别
有缓冲和无缓冲channel的声明
下面简要说明它们之间的区别,先声明两个channel分别有缓冲1和无缓冲:
c1 := make(chan int) // 无缓冲
c2 := make(chan int, 1) // 有缓冲
无缓冲的channel
下面讨论一个简单的场景:A向channel写入一个int,B从channel读走一个int,
对于c1,可以假设A和B是两个goroutine,是两个并发单位。代码如下:
c1 <- 1 // A
<- c1 // B
重点来了:这里的A或B,无论谁先执行,谁都会阻塞以等待另一个goroutine执行,也就是说往里写得等来读的,从里读得等来写的。最重要的是,A和B对c1的读写是同步的,直观的理解是A和B对c1的读写是同时发生的,当A对c1写完了,则B从c1中就读完了。这样的特性可以用于做并发单位之间的同步操作,如果在A和B中对同一个无缓冲通道进行了读写,那么A和B一定会在读写的地方进行同步,谁先到谁阻塞等待另外一个。
综上,如果在一个协程里写这样的代码,一定会死锁:
func main() {
ch := make(chan int)
ch <- 1
<- ch
}
无缓冲的channel的读写者必须同时完成发送和接收,而不能串行,显然单协程无法满足。所以这里造成了循环等待,会死锁。
缓冲为1的channel
我们依然继续上面提到的简单场景:A向channel写入一个int,B从channel读走一个int。还是一样的代码:
c2 <- 1 // A
<- c2 // B
这里和无缓冲通道不同的地方在于:有缓冲的通道并不强制channel的读写者必须同时完成发送和接收,读者只会在没有数据时阻塞,写者只会在没有可用容量时阻塞,这就有点像阻塞队列了。