golang 中 channel cap设为1原理 | 有无缓冲的channel


在golang中,如果涉及消息传递或者是并发控制等,我们常常用到 channel,channel的具体原理这里不讨论,今天主要看看有无缓冲以及缓冲值的设计。

1.无缓冲的channel

联系 channel 的数据结构 mchan 可知,就没得 buf,但 sendq recvq 这些肯定都是有的,所以在无缓冲的 channel 中,如果写者写入 channel 而没有 读者来读取数据的话,这时的写入肯定是阻塞的,同样适用于只有读者没有写者的场景,只有当读者写者都具备的情况下才会正常读写,否则阻塞或者是形成死锁。

下面看几个例子。

同个goroutine中单读channel

func TestNoCacheChanOnlyRd(t *testing.T) {
	inChan := make(chan int, 0)
	<-inChan
}

同个goroutine中单写channel

func TestNoCacheChanOnlyWr(t *testing.T) {
	inChan := make(chan int, 0)
	inChan <- 1
}

同个goroutine中有写有读

func TestNoCacheChanWrAndRd(t *testing.T) {
	inChan := make(chan int, 0)
	inChan <- 1
	<-inChan
}

不同goroutine中读写

func TestNoCacheChanWrAndRdInDiffGoroutine(t *testing.T) {
	inChan := make(chan int)
	go func() {
		fmt.Println("写入到num:", 1)
		inChan <- 1
		close(inChan)
	}()
	go func() {
		num := <-inChan
		fmt.Println("读取到num:", num)
	}()

	time.Sleep(time.Second)
	fmt.Println("主进程退出")
}

除了最后一个情况,其他情况全部都是要 deadLock 的,不信可以自己运行下。

2.有缓冲的channel

不同goroutine的读写

func TestCacheChanWrAndRd(t *testing.T) {
	intChan := make(chan int, 1)
	go func() {
		for i := 0; i < 5; i++ {
			intChan <- i
			fmt.Println("写者写入:", i)
		}
		close(intChan)
	}()
	for num := range intChan {
		fmt.Println("读者读到:", num)
	}
	fmt.Println("主进程退出")
}

因为有缓冲的存在,写者可以一直往里面写,读者在 range 遍历 channel 的时候,只要内部有数据,就可以读到数据,直到没有数据为止,如果 channel 关闭,range 也就退出了,这样就能很好实现有缓冲的 channel 的应用,这种不要求读者写者同时准备好,相当于一个阻塞队列,channel 有缓冲就可以写入,满了后面的写者就阻塞,但只要有读者就会一直读,除非 channel 没有了数据,读者也会陷入阻塞,当 channel 关闭了,则退出 channel 的遍历。

注意以下情况依然会有死锁问题。

有缓冲的 channel 只有写

func TestCacheChanOnlyWr(t *testing.T) {
	intChan := make(chan int, 1)
	intChan <- 1
}

有缓冲的 channel 只有读

func TestCacheChanOnlyRd(t *testing.T) {
	intChan := make(chan int, 1)
	<-intChan
}

总结

无缓冲的 channel 适合放在不同 goroutine 中完成读写或者数据传递等,有缓冲 channel 因为缓冲的存在,实际上就是一个阻塞队列,无缓冲 channel 的读写要求读者写者同时准备好,不然任何一方没准备好都会阻塞,有缓冲 channel 如果 cap 设为1,已经可以满足读者写者不用同时准备好,也不会陷入死锁(单写或者单读除外),而无缓冲的 channel 可能陷入死锁。

另外,有缓冲的 channel cap 设为多少根据业务场景来定,设为1是否可以满足需求,或者设为其他如1024 256 512等,根据业务来定。

以上是个人有限的认知,欢迎大神来喷。

posted on 2024-03-20 23:40  进击的davis  阅读(7)  评论(0编辑  收藏  举报

导航