03. 通道- channel

Golang 中的通道(channel)是一种用于在不同goroutine之间传递数据的机制。通道可以看作是一个管道,允许一个goroutine将数据发送到另一个goroutine。通道在并发编程中非常有用,因为它们提供了一种安全且高效的方式来进行数据交换和同步。
Golang中channel是goroutine间重要的通信方式,是并发安全的

3.1 channel 数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type hchan struct {
qcount uint32 // 队列中当前元素的数量
dataqsiz uint32 // 队列的大小
elemsize uint16 // 元素的大小
closed uint32 // 通道是否关闭
elemtype *_type // 元素类型
buf unsafe.Pointer// 指向数据队列的指针
recvx uint32 // 下一个接收元素的位置
sendx uint32 // 下一个发送元素的位置
recvq waitq // 等待接收的goroutine队列
sendq waitq // 等待发送的goroutine队列
lock mutex // 保护通道结构体的互斥锁
}


hchan结构体中的buf指向一个数组,用来实现循环队列,sendx是循环队列的队尾指针,recvx是循环队列的队头指针。dataqsize是缓存型通道的大小,qcount记录着通道内数据个数。

循环队列一般使用空余单元法来解决队空和队满时候都存在font=rear带来的二义性问题,但这样会浪费一个单元。golang的channel中是通过增加qcount字段记录队列长度来解决二义性,一方面不会浪费一个存储单元,另一方面当使用len函数查看通道长度时候,可以直接返回qcount字段,一举两得。

hchan结构体中另一重要部分是recvq,sendq,分别存储了等待从通道中接收数据的goroutine,和等待发送数据到通道的goroutine。两者都是waitq类型。

waitq是一个结构体类型,waitq和sudog构成双向链表,其中sudog是链表元素的类型,waitq中first和last字段分别指向链表头部的sudog,链表尾部的sudog。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type waitq struct {
first *sudog
last *sudog
}

type sudog struct {
...
g *g // 当前阻塞的G
...
next *sudog
prev *sudog
elem unsafe.Pointer
...
}

img.png

__END__