golang chan 踩坑 通道特性

golang 在协程中都会用到chan 用于数据同步,在并发场景下一般都会使用到这个,简单场景就是一个读取,一个写入,所以chan都是成对出现的,现在主要来说明一下有缓冲和无缓冲的场景对比。

ch1:=make(chan int)        无缓冲

ch2:=make(chan int,1)      有缓冲

ch1<- 5                            

无缓冲的 不仅仅是 向 ch1 通道放 一个int类型数据 而是 一直要有别的携程 <-ch1 接手了 这个参数,那么ch1<-5才会继续下去,要不然就一直阻塞着,所以他是读写阻塞

而 ch2<-1 则不会阻塞,因为缓冲大小是1 只有当 放第二个值的时候 第一个还没被人拿走,这时候才会阻塞。

打个比喻

无缓冲的  就是一个送信人去你家门口送信 ,你不在家 他不走,你一定要接下信,他才会走。

无缓冲保证信能到你手上

有缓冲的 就是一个送信人去你家仍到你家的信箱 转身就走 ,除非你的信箱满了 他必须等信箱空下来。

有缓冲的 保证 信能进你家的邮箱

总结:

有缓存通道的特点是,有缓存时可以向通道中写入数据后直接返回,缓存中有数据时可以从通道中读到数据直接返回,这时有缓存通道是不会阻塞的,它阻塞的场景是:

  1. 通道的缓存无数据,但执行读通道。读被阻塞
  2. 通道的缓存已经占满,向通道写数据,但无协程读,写被阻塞

     

无缓冲通道的特点是,发送的数据需要被读取后,发送才会完成,它阻塞场景:

 

  1. 通道中无数据,但执行读通道。读被阻塞
  2. 通道中无数据,向通道写数据,但无协程读取。

 另外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)
   }
}

 

上一篇:Debian Gun/linux基本用法


下一篇:select、定时器