golang 在协程中都会用到chan 用于数据同步,在并发场景下一般都会使用到这个,简单场景就是一个读取,一个写入,所以chan都是成对出现的,现在主要来说明一下有缓冲和无缓冲的场景对比。
ch1:=make(chan int) 无缓冲
ch2:=make(chan int,1) 有缓冲
ch1<- 5
无缓冲的 不仅仅是 向 ch1 通道放 一个int类型数据 而是 一直要有别的携程 <-ch1 接手了 这个参数,那么ch1<-5才会继续下去,要不然就一直阻塞着,所以他是读写阻塞
而 ch2<-1 则不会阻塞,因为缓冲大小是1 只有当 放第二个值的时候 第一个还没被人拿走,这时候才会阻塞。
打个比喻
无缓冲的 就是一个送信人去你家门口送信 ,你不在家 他不走,你一定要接下信,他才会走。
无缓冲保证信能到你手上
有缓冲的 就是一个送信人去你家仍到你家的信箱 转身就走 ,除非你的信箱满了 他必须等信箱空下来。
有缓冲的 保证 信能进你家的邮箱
总结:
有缓存通道的特点是,有缓存时可以向通道中写入数据后直接返回,缓存中有数据时可以从通道中读到数据直接返回,这时有缓存通道是不会阻塞的,它阻塞的场景是:
- 通道的缓存无数据,但执行读通道。读被阻塞
- 通道的缓存已经占满,向通道写数据,但无协程读,写被阻塞
无缓冲通道的特点是,发送的数据需要被读取后,发送才会完成,它阻塞场景:
- 通道中无数据,但执行读通道。读被阻塞
- 通道中无数据,向通道写数据,但无协程读取。
另外chan无缓存的是先进先出,代码如下:
var ch chan int = make(chan int)
func foo(id int) { //id: 这个routine的标号
fmt.Println(id)
ch <- id
}
func TestI(t *testing.T) {
// 开启5个routine
for i := 0; i < 5; i++ {
go foo(i)
}
// 取出信道中的数据
for i := 0; i < 5; i++ {
fmt.Println("out ",<- ch)
}
}