channel是Go语言中的一个核心数据类型,负责go协程的2个问题:(1)同步问题;(2)协程之间数据共享(数据传递)。
goroutine 通过通信来共享内存,而不是共享内存来通信。
一、无缓冲通道
1、 声明一个无缓冲通道时,不需要声明容量。
在没有准备就绪的接收者的时候,第一个 goroutine 在发送消息后channel将被阻塞。
如果通道是无缓冲的,发送者将被阻塞,直到接收者接收到值。
2、声明无缓冲通道
var ch = make(chan int)
3、定义1个函数,循环输出10次。
len(ch):表示使用了xx个通道
cap(ch):表示还剩下xx个通道
func User1() {
for i := 0; i < n; i++ {
ch <- i
fmt.Printf("User1协程正在运行 , 经历了 %v 秒,使用了%v个,还剩%v个 \n", i, len(ch), cap(ch))
}
}
4、在主函数中,建子协程,运行函数user1。
循环获取通道内的数值,由于是无缓冲通道,那么就等待子协程传递进来1个后,才可以继续执行顺序代码。
go User1()
for i := 0; i < n; i++ {
x := <-ch
time.Sleep(time.Second * 1)
fmt.Printf("当前管道内的值是:%v\n", x)
}
5、执行结果
可以看到,在无缓冲通道的时候,channel内,使用和剩余管道内始终为0,因为通道内在没有阻塞的时候,通道内是不存在数据的。
因此代码才是进通道1个数据后,等待从通道内取走数据,否则将等待;当数据取走后,通道才可以有接受新数据的能力。
二、有缓冲通道
1、 声明一个有缓冲通道时,需要提前声明通道的容量。
当通道是有缓冲时,发送者将数据持续发到通道内,直到达到容量最大值,后才被阻塞,直到接收者接收到值,每当接受1个值后,通道腾出1个位置继续接受传递进去的值。
2、创建1个有缓冲通道,缓存容量为1
var c = 1
var ch = make(chan int, 1)
3、定义1个函数,循环输出10次。
len(ch):表示使用了xx个通道
cap(ch):表示还剩下xx个通道
func User1() {
for i := 0; i < n; i++ {
ch <- i
fmt.Printf("User1协程正在运行 , 经历了 %v 秒,一共%v个通道,使用了%v个,还剩%v个 \n", i, c, len(ch), cap(ch))
}
}
4、在主函数中,建子协程,运行函数user1。
循环获取通道内的数值,由于是有缓冲通道,那么就等待子协程传递进来1个后,才可以继续执行顺序代码。
func main() {
go User1()
for i := 0; i < n; i++ {
x := <-ch
time.Sleep(time.Second * 1)
fmt.Printf("当前管道内的值是:%v\n", x)
}
}
5、执行结果
可以看到,在有缓冲通道的时候,channel内,每当执行1次,通道内可用容量减1,直到最大容量时,等待从通道内取走数据,通道阻塞。当数据取走后,通道才可以有接受新数据的能力。