在写代码的时候,我们很多时候都会用到channel,但是channel是如何实现的呢?
基于上一篇文章
Go语法实现分析之chan、go func、类型转换_程序员红豆的博客-CSDN博客声明、初始化代码,我们都懂,但是它背后是怎么实现的呢?https://blog.csdn.net/qq_37186127/article/details/125521611我们来分析分析channel的实现
我们先看chan.go的hchan结构
- type hchan struct {
- qcount uint // total data in the queue
- dataqsiz uint // size of the circular queue
- buf unsafe.Pointer // points to an array of dataqsiz elements
- elemsize uint16
- closed uint32
- 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
- }
qcount:channel当前的数据总数
dataqsiz:channel的大小
buf:用于存储数据的环形队列指针
closed:是否已经关闭
sendx:发送索引
recvx: 接收索引
recvq:当缓冲信道接收阻塞的时候,用于挂载sudog
sendq: 当缓冲信道发送阻塞的时候,用于挂载sudog
无缓冲信道就没什么好了解的了,因为直接阻塞
我们接下来看下有缓冲信道是怎么实现的
我们可以看到,当我们向ch发送两条数据的时候,qcount变成了2,buf里面多了7、8两个元素
sendx也变成了2,意味着下一次发送进来的数据是存储到buf[2]这里
上述代码初始化了一个容量大小为3的信道,并且向信道发送了3个数据
这时候channel是数据是满了,那么接下来的数据发送就会进行阻塞
我们可以发现qcount变成了3,sendx变成了0
那么阻塞的数据channel会如何处理呢?
阻塞的数据会形成一个sudog被挂到sendq数据结构下
如果我们从一个空channel里接收数据,那么也会形成阻塞[1],并形成一个sudog,挂到recvq下
如果我们从buf中消费一个数据的时候,recvx也会随之改变
本文完~