管道channel基本介绍
channel的介绍
- channel的本质就是一个队列,数据先进先出
- 管道是线程安全的,多goroutine访问时,无需加锁
channel基本使用
1 | // 声明 |
注意:
- channel是引用类型(是指针,初始化后才能使用)
- channel是有对应数据类型的
空接口实现存放任意类型的管道
由于任何类型都实现了空接口,即空接口变量可以被赋予任何类型的变量,所以可以利用用空接口实现可以存放任意类型的管道
1 | // 利用空接口定义一个可以存放任何数据类型的管道 |
注意:
从空接口类型的管道中取出数据时,注意类型断言
管道的关闭和遍历
管道的关闭
1 | func close(c chan<- Type) |
使用内置函数close
可以关闭管道,当管道关闭时不能再向管道写数据,但仍可以从管道中读数据
对于已关闭并且没有数据的管道,语句:
1 | x, ok := <-c |
还会将ok置为false。
管道的遍历
channel支持for-range遍历,注意:
- 如果管道没有关闭,则出现
deadlock
错误(不向管道中发送数据,会一直阻塞) - 如果管道已经关闭,可以结束遍历
1 | // 管道的遍历 |
无缓冲区和有缓冲区管道
有缓冲区管道
在有缓冲区的管道中,只要不超过缓冲区大小,不会出现写阻塞
1 | // 创建有3个缓冲区大小的管道 |
无缓冲区的管道
在没有缓冲区的管道中,只要管道中的数据没有被拿走,始终会阻塞发送方
1 | var intChan = make(chan int) |
上述代码一定会输出hello world
,因为在发送方向管道写数据时,由于没有接收方管道会被直接阻塞。当有接收方想要从管道中读取数据时,发送方才会被唤醒。
只读/只写管道
在默认情况下,管道时双向的,可读可写。
但是管道是可以声明为只读或者只写的。
只写管道
只写管道的数据类型为chan<- 管道数据类型
只读管道
只读管道的数据类型为<-chan 管道数据类型
应用场景
若有两个协程send和recv,send只负责发送数据,recv只负责接收数据。
1 | // send只负责发送数据,故只向管道中写数据 |
1 | // recv只负责接收数据,故只从管道中读取数据 |
select关键字
select
可以解决从管道取数据的阻塞问题。类似于switch
语句,每个case
必须是一个通信(管道)操作,要么发送要么接收。
select
随机执行一个可运行的 case
。如果没有case
可运行,它将阻塞,直到有case
可运行。
如果有多个case
都可以运行,select
会随机公平地选出一个执行。其他不会执行。
1 | for { |