了解下
缓冲通道就是指一个通道,带有一个缓冲区。发送到一个缓冲通道只有在缓冲区满时才被阻塞。类似地,从缓冲通道接收的信息只有在缓冲区为空时才会被阻塞。 可以通过将额外的容量参数传递给make函数来创建缓冲通道,该函数指定缓冲区的大小。
代码看看
package main
import "fmt"
func main() {
ch01 := make(chan int)
// 默认都是 0 0
// 非缓冲的通道可以理解为容量 = 0
fmt.Println(len(ch01),cap(ch01))
// 缓冲通道可以理解为有容量定义的通道
ch02 := make(chan int,5)
// 0 5
fmt.Println(len(ch02),cap(ch02))
// 这时候我们向缓冲通道写入一个数据
ch02 <- 100
// 长度 = 1 容量 = 5 缓冲区还有 4 个容量
// 并且写入时没有被阻塞
fmt.Println(len(ch02),cap(ch02))
// 还有 4 个坑,那继续向通道写入 4 个数据
ch02 <- 100
ch02 <- 100
ch02 <- 100
ch02 <- 100
// 长度 = 5 容量 = 5 缓冲区已经没有了容量了
fmt.Println(len(ch02),cap(ch02))
// 如果这时候作死,再向通道写一个数据
ch02 <- 100
// 就会遇到死锁了,fatal error: all goroutines are asleep - deadlock!
// 因为这时候没有其他的来帮他解除阻塞了
}
执行
0 0
0 5
1 5
5 5
fatal error: all goroutines are asleep - deadlock!
特性分析
本质上,缓冲通道是在阻塞执行的时候建立一个
缓冲区当缓冲区空了的时候,写入就会进入阻塞,同样的读也会进入阻塞,最终造成死锁 所以应用场景上,只是在 channel 通道的基础上建立缓冲,来缓解阻塞的压力
看这个示例
package main
import (
"fmt"
"time"
)
var chA chan int
func main() {
chA = make(chan int,10)
// 子 goroutine 执行
go sends()
// 循环向通道 ch 读取数据
for value := range chA {
fmt.Println("主 goroutine 读取通道 chA 的值:",value)
}
fmt.Println("运行结束")
}
func sends() {
for i := 1; i < 6; i++ {
time.Sleep(1 * time.Second)
fmt.Println("子 goroutine 向通道 chA 写入:",i)
chA <- i
}
fmt.Println("关闭通道 ch ")
close(chA)
}
执行的结果
主 goroutine 读取通道 chA 的值: 1
子 goroutine 向通道 chA 写入: 2
主 goroutine 读取通道 chA 的值: 2
子 goroutine 向通道 chA 写入: 3
主 goroutine 读取通道 chA 的值: 3
子 goroutine 向通道 chA 写入: 4
主 goroutine 读取通道 chA 的值: 4
子 goroutine 向通道 chA 写入: 5
关闭通道 ch
主 goroutine 读取通道 chA 的值: 5
运行结束