底层数据结构
源码( go 1.9.2)
1 | type hchan struct { |
重点字段
buf
指向底层循环数组,只有缓冲型的 channel 才有。sendx
,recvx
均指向底层循环数组,表示当前可以发送和接收的元素位置索引值(相对于底层数组)。sendq
,recvq
分别表示被阻塞的 goroutine,这些 goroutine 由于尝试读取 channel 或向 channel 发送数据而被阻塞。waitq
是sudog
的一个双向链表,而sudog
实际上是对 goroutine 的一个封装:
1 | type waitq struct { |
lock
用来保证每个读 channel 或写 channel 的操作都是原子的。
例如,创建一个容量为 6 的,元素为 int 型的 channel 数据结构如下 :
channel的创建过程
通道有两个方向,发送和接收。理论上来说,可以创建一个只发送或只接收的通道,但是这种通道创建出来后,怎么使用呢?一个只能发的通道,怎么接收呢?同样,一个只能收的通道,如何向其发送数据呢?
一般而言,使用 make
创建一个能收能发的通道:
1 | // 无缓冲通道 |
创建 chan 的函数是 makechan
:
1 | func makechan(t *chantype, size int64) *hchan |
从函数原型来看,创建的 chan 是一个指针。所以能在函数间直接传递 channel,而不用传递 channel 的指针。
具体过程:
1 | const hchanSize = unsafe.Sizeof(hchan{}) + uintptr(-int(unsafe.Sizeof(hchan{}))&(maxAlign-1)) |
新建一个 chan 后,内存在堆上分配,大概长这样: