channel是不同协程之间异步通信的数据结构。
基本用法
1 构造
ch:=make(chan int)//无缓冲
ch:=make(chan int,10)//有缓冲
2 读操作
val:=<-ch
<-ch
val,ok:=<-ch
3 写
var data int
ch<-data
4 关闭
close(ch)
5 多路复用
select{
case <-parent.Done():
child.cancel(false,parent.Err())
case <-child.Done():
}
实现对多个channel同时监听
select{
case <-ch1://读
// do some logic
case ch3 <-data://写
// do some logic
default:
// 放行
}
核心数据结构
三个核心:
1 并发读写安全,需要锁
2 环形缓冲区(数组+头尾指针),好处是复用数组空间,同时保证内存地址连续
3 承载阻塞goroutine的队列
type hchan struct{ // runtime包下
qcount unit // total data in the queue
dataqsize uint // size of the circular queue
buf unsafe.Pointer // points to an array of dataqsiz elements
elemsize uint 16
closed uint 32
elemtype *_type //element type
sendx uint //send index
recvx uint //receive index
sendq waitq // list of send waiters
recvq waitq //list of recv waiters
lock mutex
}
hchan:channel数据结构
- qcount:当前channel中存在多少个元素
- dataqsize:当前channel中能存放的元素容量
- buf:channel中用于存放元素的环形缓冲区
- elemsize:channel中存放元素类型的大小
- closed:标识channel是否关闭
- elemtype:channel元素类型
- sendx:发送元素进入环形缓冲区的index
- recvx:接收元素所处的环形缓冲区的index
- sendq:因发送而陷入阻塞的协程队列
- recvq:因接收而陷入阻塞的协程队列
type waitq struct{ // 阻塞的协程队列
first *sudog // 队列头部
last *sudog //队列尾部
}
type sudog struct{ // 阻塞的协程队列
g *g
prev *sudog // 队列头部
next *sudog //队列尾部
elem unsafe.Pointer // data element(may point to stack)
isSelect bool
c *hchan
}
- sudog:用于包装协程的节点
- g:goroutine,协程
- prev:队列中的上一个节点
- next:队列中的下一个节点
- isSelect:标识当前协程是否处在select多路复用的流程中
- c:标识与当前sudog交互的chan