Golang Channel底层实现原理

1、本文讨论Channel的底层实现原理

首先,我们看Channel的结构体

在这里插入图片描述

简要介绍管道结构体中,几个关键字段

在Golang中,管道是分为有缓冲区的管道和无缓冲区的管道。

这里简单提一下,缓冲区大小为1的管道和无缓冲区的管道的区别,如果是

缓冲区大小为1的管道,发送者A发送数据后,发送者A可以去干其它行为,但是别的发送者想发送数据,会阻塞。对于发送者A来说,这是一个非阻塞行为

无缓冲区的管道的区别,发送者A发送数据后,发送者A会被阻塞,直到管道数据被读取,发送者A才会被唤醒,对于发送者A来说,这是一个阻塞行为

回归正题buf是一个指针变量,当有缓冲区时,指向保存数据的底层数组sendx指的是,当前管道发送数据最后位置recvx是当前管道接收数据的最后一个位置,其实这样就构成了一个循环队列,如图
在这里插入图片描述

recvq是等待接收队列,该队列实现的数据结构是双链表,链表节点可以理解成协程,保存的是被管道阻塞的协程。

sendq是等待发送队列,该队列实现的数据结构是双链表,链表节点可以理解成协程,保存的是被管道阻塞的协程。

其实管道可以理解成数据通信方式中的共享空间,对于共享空间的变量读写,为了保证并发数据的一致性,所以需要加锁,所以lock字段就是锁,而且是悲观锁

所以 管道 收发数据是要加锁的

再给大家分享一些关于管道的理解吧

(1)当向未关闭,但是缓冲区已满的管道发送数据,或者缓冲区为空的管道读取数据就会阻塞,阻塞的协程加入感到的发送等待队列或接收等待队列

(2)使用channel的时候,也需要注意管道是否会发生gorountine泄漏,比如一个G****一直阻塞在一个不会改变状态的管道的时候,这个G不会结束,这个G的内存空间无法回收。一个G的内存空间大概就几KB,但是还是取决于你的栈有多大。

(3)包括关闭channel的时候,关闭channel的原则主要有
----①不要已关闭的管道发送数据
----②不要关闭已关闭的管道
----③所以,关闭管道主要有以下几个场景
--------1)如果是一个发送者,都让发送者关闭
--------2)如果是多个发送者,一个接收者
----------------a.可以是用一个传递信号的管道,让每个发送者去for+select去监听,然后接收者负责关闭 传递信号 的管道。当接收者关闭这个管道,发送者那边select的case最终肯定会进入,然后让发送者退出。这里面并不去实际关闭传送数据的管道
--------3)如果是多个发送者,多个接收者
----------------a.可以用一个中间人,去接收关闭信号,然后去关闭传递信号的管道,关闭后这个中间人协程就退出。任一发送者、接收者都可以发送关闭的信号,全部发送者、接收者都for+select监听关闭信号的管道,和多个发送者、一个接收者类型,通过中间人 只关闭一次,避免了重复关闭导致的Panic
-------4)如果多个发送者都由一个父协程产生的,那就让父协程来关闭

  • 38
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值