go有缓冲channel和无缓冲channel
我们都知道通道(channel)分两种:
- 缓冲通道
- 非缓冲通道
// 缓冲通道 ch1 := make(chan int, 10) ch2 := make(chan bool, 2) // 非缓冲通道 ch3 := make(chan int) ch4 := make(chan bool, 0)
发送通道数据
// 创建一个空接口通道,注意定义的通道类型有
ch := make(chan interface{})
// 将0放入通道中
ch <- 0
// 将hello字符串放入通道中
ch <- "hello"
接收通道数据
阻塞接收数据
data := <-ch
执行该语句时将会阻塞,直到接收到数据并赋值给 data 变量。
非阻塞接收数据
// data:表示接收到的数据。未接收到数据时,data 为通道类型的零值 // ok:表示是否接收到数据。 data, ok := <-ch
非阻塞的通道接收方法可能造成高的 CPU 占用,因此使用非常少。如果需要实现接收超时检测,可以配合 select 和计时器 channel 进行,可以参见后面的内容。
接收任意数据,忽略接收的数据
<-ch
循环接收
package main import ( "fmt" "time" ) func main() { ch := make(chan int) // 开启一个并发匿名函数 go func() { for i := 3; i >= 0; i-- { ch <- i time.Sleep(time.Second) } }() // 遍历接收通道数据 for data := range ch { fmt.Println(data) if data == 0 { break } } }
关闭通道
ch := make(chan string)
...
close(ch)
通道特性:
- 同一个通道,发送操作之间是互斥的,接收操作之间也是互斥的(并发安全)
- 发送操作和接收操作中对元素值的处理都是不可分割的。
- 发送操作在完全完成之前会被阻塞,接收操作也是一样。
- 对于缓冲通道:如果通道已满,那么对它的所有发送操作都会被阻塞,直到通道中有元素值被接收走;如果通道已空,那么对它的所有接收操作都会被阻塞,直到通道中有新的元素值出现。
对于非缓冲通道:无论是发送操作还是接收操作,一开始执行就会被阻塞,直到配对的操作也开始执行,才会继续传递。
注意点:
关闭通道要在发送方关闭,关闭后如果channel内还有元素,并不会对接下来的接收产生影响
单向通道最主要的用途就是约束其他代码的行为
通过函数的参数类型或者返回值类型来限制(Go的语法糖)。
func(ch chan<- int) //传入双向通道,在函数里面调用ch只能发送
func() (ch <-chan int) //返回双向通道,在函数外面里面调用ch只能接收
那么非缓冲通道是不是就是缓冲size为1的缓冲通道呢?我们来测试下:
func TestChan(t *testing.T) {
ch := make(chan int)
ch <- 1
go func() {
<-ch
}()
ch <- 2
}
func TestChan2(t *testing.T) {
ch := make(chan int, 1)
ch <- 1
go func() {
<-ch
}()
ch <- 2
}
go test 运行一下,会发现TestChan阻塞住了,ch <- 1 不能写在go func 前面,那么非缓冲通道显然不是就是缓冲size为1的缓冲通道。非缓冲通道像是以前的快递员,必须有收货人当面接收成功,否则他会等着你送货,有缓冲通道更像是现在的快递员,直接放在驿站或者快递柜,除非驿站快递柜满了,否则他就胡塞,不管你在不在家,有没有接收成功。
go有缓冲channel和无缓冲channel
https://blog.puresai.com/2022/01/11/382/