golang channel通道的数据结构底层原理

本文详细介绍了Golang中的Channel,作为语言级别的协程通信机制,Channel在进程内部实现goroutine间的通信。文章剖析了Channel的数据结构,包括队列长度、元素大小和等待队列等,并解释了数据写入和读取的过程,以及关闭Channel的影响。通过对Channel的工作原理的深入理解,有助于提升Golang并发编程的能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、channel

  1. channel 是 golang 提供的语言层面的携程,主要用于进程内部goroutine 之间的通信,跨进程之间的通信还得使用分布式方式来解决。

  2. channel数据结构

    type hchan struct {
        qcount   uint           // 当前队列中剩余元素个数
        dataqsiz uint           // 环形队列长度,即可以存放的元素个数
        buf      unsafe.Pointer // 环形队列指针
        elemsize uint16         // 每个元素的大小
        closed   uint32         // 标识关闭状态
        elemtype *_type         // 元素类型
        sendx    uint           // 队列下标,指示元素写入时在队列中的位置
        recvx    uint           // 队列下标,指示元素从队列的该位置读出
        recvq    waitq          // 等待读消息的goroutine队列
        sendq    waitq          // 等待写消息的goroutine队列
        lock mutex              // 互斥锁,chan不允许并发读写
    }
    
  3. 请添加图片描述

  4. 。buf 是环形队列的首地址
    。dataqsiz 是队列长度
    。qcount 队列还剩余俩个元素的空间
    。sendx 3 待写入的数据存储下标位置
    。recvx 1 从该位置读取数据
    . recvq 从channel读数据的goroutine ,如果缓冲区为空或没有缓冲区,当前goroutine阻塞
    。sendq 向channel中写入数据的goroutine,如果缓冲区已满或没有缓冲区,当前goroutine阻塞。
    。因读阻塞的goroutine 会被写goroutine唤醒
    。因写阻塞的 goroutine会被读goroutine唤醒
    
    

请添加图片描述

  1. 上图是没有传冲区的channel,一般情况下至少一个为空。当同一个goroutine 使用select同时,读写

  2. 类型,elemtype 表示数据传递时的数据结构。elemsize表示类型大小

  3. 锁,lock同时只能被一个goroutine 读写

  4. func makechan(t *chantype, size int) *hchan {
        var c *hchan
        c = new(hchan)
        c.buf = malloc(len(chantype) * size)
        c.elemsize = len(chantype)
        c.elemtype = chantype
        c.dataqsiz = size
    
        return c
    }
    //创建channel的过程c := make(chan int,7)就是初始化hchan的过程
    
  5. 请添加图片描述

  6. 向channel中写入数据的过程
    。 如果缓冲区qcount有空余位置,直接将数据写入缓冲区,结束发送过程
    。如果缓冲区没有空余位置,将待发送数据写入G,将当前G加入sendq,进入睡眠,等待G被唤醒
    。如果recvq 不为空,说明有多余的G等待读取数据,那么从recvq 中读取一个G 把数据直接吸入G,唤醒G->结束发送
    。如果recvq为空,buf不为空时,将G加入sendq等待唤醒;buf为空时,将数据写入 buf对位-> 结束发送
    

11.从channel读数据[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DvlQ7PFM-1666181905633)(D:\Download\typora\golang\go专家编程\m_933ca9af4c3ec1db0b94b8b4ec208d4b_r.png)]

。如果等待发送队列sendq不为空,且没有缓冲区,直接从sendq取G,把G中数据读出,把G唤醒,结束读取
。如果等待发送队列
  1. 关闭channel,把recvq 中的G全部唤醒,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小哥(xpc)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值