Channel的作用
协程间通信
数据传递:channel可以让一个goroutine发送数据,另一个goroutine接收数据。例如,在一个网络服务器程序中,一个goroutine可能负责接收客户端连接并将请求数据放入channel,另一个goroutine从channel中取出请求数据进行处理。
数据结构
type hchan struct {
qcount uint // total data in the queue 队列中数据总数
dataqsiz uint // size of the circular queue 环形队列size大小
buf unsafe.Pointer // points to an array of dataqsiz elements (环形队列)
elemsize uint16 // 元素大小
closed uint32 // 关闭
timer *timer // timer feeding this chan
elemtype *_type // element type 元素类型
sendx uint // send index 已发送数据在环形队列的位置
recvx uint // receive index 已接受数据在环形队列的位置
recvq waitq // list of recv waiters 接收者等待队列
sendq waitq // list of send waiters 发送者等待队列
// lock protects all fields in hchan, as well as several
// fields in sudogs blocked on this channel.
//
// Do not change another G's status while holding this lock
// (in particular, do not ready a G), as this can deadlock
// with stack shrinking.
lock mutex
}
type waitq struct {
first *sudog
last *sudog
}
如何保证协程安全
lock mutex
无缓冲区的Channel
reveq:从Channel
中接受元素,如果没有元素则会直接阻塞等待
// Signal to anyone trying to shrink our stack that we're about
// to park on a channel. The window between when this G's status
// changes and when we set gp.activeStackChans is not safe for
// stack shrinking.
gp.parkingOnChan.Store(true)
gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanSend, traceBlockChanSend, 2)
sendq:向Channel
中发送元素,如果没有接收者则会直接阻塞等待
goready(gp, skip+1)
lock 读写锁
有缓冲区的Channel
从缓冲区中读取数据,用数组建立的一个环形链表
不会产生阻塞操作