GoLang之图解channel之数据结构

图解channel之数据结构

注:本文以Windos上Go SDK v1.18进行讲解

channel被设计用来实现goroutine间的通信,按照golang的设计思想:以通信的方式共享内存。
如下代码中的make函数会在堆上分配一个runtime.hchan类型的数据结构,ch是存在于函数f栈帧上的一个指针,指向堆上的hchan数据结构。

func f() {
    ch := make(chan int)
    ...
}

至于为什么是堆上的一个结构体?自然是因为这种被设计用来实现协程间通信的组件,其作用域和生命周期不可能仅限于某个函数内部,所以golang直接将其分配在堆上。

在这里插入图片描述

channel分为“无缓冲”和“有缓冲”两种,对于有缓冲channel来讲,需要有相应的内存来存储数据,实际上就是一个数组。
hchan需要记录数组的地址、容量、元素的大小,以及已有元素个数。
又因为golang运行时中,内存复制、垃圾回收等机制依赖数据的类型信息,所以hchan中还要有一个指针,指向元素类型的类型元数据。

在这里插入图片描述

channel支持交替的读写(称send为写,recv为读,更简洁),有缓冲channel内的缓冲数组会被作为一个“环型”来使用,当下标超过数组容量后会回到第一个位置,所以要分别记录读写下标的位置。

当读和写操作不能立即完成时,需要能够让当前协程在channel上等待,当条件满足时,要能够立即唤醒等待的协程,所以要有两个等待队列,分别针对读和写。

在这里插入图片描述

等待队列是runtime.sudog类型的双向链表,sudog中会记录是哪个协程在等待,等待哪一个channel等等。
特别是sudog.elem这个成员,对于recvq中的sudog而言,它代表recv到数据以后要存储到哪里;对于sendq中的sudog而言,它代表要send的数据在哪里。

在这里插入图片描述

对ch1而言,目前它的缓冲区已满,接下来读出一个元素,注意观察读写下标的变化。

v <- ch1

在这里插入图片描述
在这里插入图片描述

type hchan struct {
    qcount   uint           // 数组长度,即已有元素个数
    dataqsiz uint           // 数组容量,即可容纳元素个数
    buf      unsafe.Pointer // 数组地址
    elemsize uint16         // 元素大小
    closed   uint32
    elemtype *_type // 元素类型
    sendx    uint   // 下一次写下标位置
    recvx    uint   // 下一次读下标位置
    recvq    waitq  // 读等待队列
    sendq    waitq  // 写等待队列
    lock     mutex
}

在这里插入图片描述
在这里插入图片描述

好啦,了解了channel的数据结构,再去理解channel的读、写、关闭操作,就容易得多了!(未完待续~)

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GoGo在努力

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值