深入解析Go Channel各状态下的操作结果
深入解析Go Channel各状态下的操作结果
作者:渔夫子 2023-06-15 08:06:55网络 网络管理 golang中的通道就是用来在协程间进行通信的。我们从源码级别推导了针对通道的各个状态下的操作所产生的结果。大家好,我是渔夫子。
channel是golang中独有的特性,也是面试中经常被问到的。相信大家都看到过下面这张图,对于不同状态下通道,在操作时会有什么结果。
这张图总结的非常好。但我们不能死记硬背这些结果。要了解其底层的基本原理,就能理解这些结果是怎么来的。
我们分三部分来讲。先是channel的基础使用,基础使用提现了channel有哪些特性。再引出channel的底层数据结构。底层数据结构就是围绕这些特性而建立的。最后再看go是如何基于底层数据结构来实现这些特性的。
channel的基础使用
通道的定义和初始化
通过var定义通道
通过var定义一个通道变量ch,这个变量能够接收整型的数据。当然也可以指定其他任何数据类型。
var ch chan intch 代表变量名chan固定值。代表ch是通道类型int代表在通道ch中存储的是整型数据。ch变量的默认值是nil。对于nil通道在操作时会有特殊的场景,一会我们也会讲解。通过make初始化通道
通过make可以初始化无缓冲区通道和缓冲区通道。区别就在于make中是否指定了缓冲区的大小。如下:
var ch = make(chan int) //初始化无缓冲通道var ch = make(chan int, 10) //缓冲区通道,缓冲区可以存10个元素无缓冲通道和有缓冲通道的区别可以从属性上和行为两方面来体现:
从属性上区别:通道是否有一段缓冲区来暂存元素。从行为上区别:发送者和接收者是否同步的还是异步的。从底层数据结构上区别:是否有一块缓冲区来暂存数据。这个后面会详细讲解。通道的操作
golang中对于通道有三种操作:往通道中发送元素、从通道中接收元素、关闭通道。如下:往通道中发送元素:
var ch chan int = make(chan int, 10)2 ->ch //发送元素var item intitem <-ch //接收元素close(ch) //关闭元素总结一下:
通道有三种操作:发送、接收和关闭。通道有三种类型:nil通道、无缓冲通道和有缓冲通道。通道有2种状态:关闭状态和未关闭状态。缓冲通道的未关闭状态又可以分为缓冲区满、缓冲区未满状态。那么,通道是基于怎样的数据结构来完成这些行为的呢?
channel的数据结构
我们先给出channel的底层数据结构,如下:
type hchan struct { qcount uint // total data in the queue dataqsiz uint // size of the circular queue bufunsafe.Pointer // points to an array of dataqsiz elements elemsize uint16 closed uint32 elemtype *_type // element type sendxuint // send index recvxuint // receive index recvqwaitq// list of recv waiters sendqwaitq// 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}type waitq struct { first *sudog last*sudog}根据上面的结构定义,依次解释下各个字段的含义:
buf:指向一个数组,代表的是一个队列,结合sendx和recvx字段实现了环形队列。缓存对应的元素。缓冲区通道就是利用这个字段实现的。qcount:在buf队列中当前有多少个元素。dataqsiz:代表队列buf的容量。在使用make进行初始化时,指定的元素个数就存在该字段中。elemsize:一个元素的字节大小。根据该元素的大小,可以初始化buf的容量的大小。通过elemsize*容量就能知道该给buf分配多少字节的空间了。closed:代表该通道是否被关闭。其值只有0和1。1代表该通道已经关闭了。0代表未关闭。elemtype:代表元素的类型。sendx:代表的是发送下一个元素应该存储的位置recvx:代表的是下一个接收元素的位置。recvq:代表的是等待接收元素的协程队列sendq:代表的是发送元素的协程队列。根据以上结果,绘制成图会容易理解点,如下:
缓冲通道和非缓冲通道的区别
从定义上,缓冲通道和非缓冲通道都是通过make来初始化的。不同点在于是否在make函数上指定了通道的容量大小。如下:
unbufferCh := make(chan int) //初始化非缓冲区通道bufferCh := make(chan int, 10) //初始化一个能缓冲10个元素的通道从通道的底层数据结构上来说,非缓冲渠道不会初始化结构体中的buf字段。而缓冲渠道则会初始化buf字段。该字段指向一块内存区域。如下图:
通道的发送、接收流程
通过源码我们梳理出来了给通道发送数据和从通道中接收数据的流程图。这张流程图将缓冲通道和无缓冲通道两种状态下的发送和接收流程都包含了,所以看起来会比较复杂。但是没关系,下面我们会分解这张图。
通过上面的流程,大家需要注意的一点就是,无论是在发送还是接收操作时,都是优先从等待队列中获取对应的线程,如果有,则直接接收或发送;如果等待队列没有协程,然后再看是否有缓冲区。这一点需要大家额外注意。
各状态通道的操作
无缓冲通道
根据上述无缓冲通道其实本质上就是没有缓冲区。在初始化时不指定make的容量即可。实际上这也叫做同步发送和接收。针对这种状态的通道,当发送数据时,如果接收队列中有等待的接收协程,那么就能发送成功;否则,进入阻塞状态。反之,亦然。其流程图就是图中的红色箭头部分,如下:
再简化一下就是:
往无缓冲区中发送数据时,如果有等待接收的协程,则发送成功;否则,发送协程进入阻塞状态。从无缓冲区接收数据时,如果有等待发送的协程,则接收成功;否则,接收协程进入阻塞状态。那么,上面的图可以简化成如下:
另外需要额外注意一点,对于非缓冲区通道的发送和接收操作。如果是在main函数中进行发送和接收,那么会造成死锁。如下:
func main() { var ch = make(chan int) <-ch fmt.Println("the End")}//或func main() { var ch = make(chan int) ch <- 2 fmt.Println("the End")}所以,对于非缓冲区通道的发送和接收操作,最主要的问题就是可能会造成阻塞。除非,两个发送和接收协程都存在,而且要在不同的协程里。
有缓冲通道
有缓冲区通道就是在通道中有一块缓冲区,发送和接收都可以针对缓冲区进行操作。也称为异步发送和接收。在有缓冲通道的状态下,j对于发送操作来说,有缓冲通道的状态分为缓冲区满和未满两种状态。根据上面的发送流程图来说,当缓冲区满了,自然就不能再发送了,就会进入等待发送队列。同时阻塞,等待被接收协程唤醒。
对于接收操作来说,有缓冲通道的状态分为缓冲区空和未满两种状态。同样,如果当缓冲区空时,无数据可接收,自然就进入到接收等待队列。同时进入阻塞,等待被发送协程唤醒。
已关闭状态的通道
关闭通道是通过**close**函数进行的。本质上关闭一个通道,就是将通道结构中的closed字段置为 1。从源代码中可以获知:
关闭nil通道:panic关闭已经关闭了的通道:panic。这一点可以这样理解,关闭一个已经关闭的通道是没有任何意义的。发送消息到已关闭的通道
给已经关闭了的通道发送消息会引发panic。这个很好理解,因为通道已经关闭,就是为了不让发消息了。如下代码:
从已关闭的通道接收消息
从已关闭的通道中接收消息时,都能操作成功。但会根据通道中是否有元素有以下不同:
如果通道中已经没有元素了,则会返回一个false的状态。如果通道中有元素,则会继续接收通道中的元素,直到接收完,并返回false。你看,其实代码也很简单。我们将代码拆解一下,就是右侧的流程图。
nil通道
通过以下方式定义的通道类型的变量,其默认值就是nil。
var ch chan intnil通道相当于没有分配通道的底层结构
如下是从源代码中截取的各个操作以及对应操作结果。通过源代码可获知:
关闭nil通道会panic从nil通道接收、发送消都会阻塞总结
golang中的通道就是用来在协程间进行通信的。我们从源码级别推导了针对通道的各个状态下的操作所产生的结果。最后总结一下:缓冲区通道:
只要有缓冲空间就能发送成功。除非缓冲空间满了,则产生阻塞。只要缓冲空间中有元素就能接收成功。除非没有元素,则产生阻塞。nil通道:
nil通道是没有初始化底层数据结构的通道。因为没有空间可存储任何元素,所以发送和接收都会产生阻塞。关闭nil通道,则会引发panic。已关闭的通道:
往已关闭的通道中发送消息,会引发panic。从已关闭通道中接收消息,会成功。关闭已关闭的通道,也会引发panic。 责任编辑:武晓燕 来源:Go学堂 gogolang通信推荐系统
电脑公司Ghost Win8.1 x32 精选纯净版2022年7月(免激活) ISO镜像高速下载
语言:中文版系统大小:2.98GB系统类型:Win8电脑公司Ghost Win8.1x32位纯净版V2022年7月版本集成了自2022流行的各种硬件驱动,首次进入系统即全部硬件已安装完毕。电脑公司Ghost Win8.1x32位纯净版具有更安全、更稳定、更人性化等特点。集成最常用的装机软件,精心挑选的系统维护工具,加上绿茶独有
微软Win11原版22H2下载_Win11GHOST 免 激活密钥 22H2正式版64位免费下载
语言:中文版系统大小:5.13GB系统类型:Win11微软Win11原版22H2下载_Win11GHOST 免 激活密钥 22H2正式版64位免费下载系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。Win11 64位 Office办公版(免费)优化 1、保留 Edge浏览器。 2、隐藏“操作中心”托盘图标。 3、保留常用组件(微软商店,计算器,图片查看器等)。 5、关闭天气资讯。
Win11 21H2 官方正式版下载_Win11 21H2最新系统免激活下载
语言:中文版系统大小:4.75GB系统类型:Win11Ghost Win11 21H2是微软在系统方面技术积累雄厚深耕多年,Ghost Win11 21H2系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。Ghost Win11 21H2是微软最新发布的KB5019961补丁升级而来的最新版的21H2系统,以Windows 11 21H2 22000 1219 专业版为基础进行优化,保持原汁原味,系统流畅稳定,保留常用组件
windows11中文版镜像 微软win11正式版简体中文GHOST ISO镜像64位系统下载
语言:中文版系统大小:5.31GB系统类型:Win11windows11中文版镜像 微软win11正式版简体中文GHOST ISO镜像64位系统下载,微软win11发布快大半年了,其中做了很多次补丁和修复一些BUG,比之前的版本有一些功能上的调整,目前已经升级到最新版本的镜像系统,并且优化了自动激活,永久使用。windows11中文版镜像国内镜像下载地址微软windows11正式版镜像 介绍:1、对函数算法进行了一定程度的简化和优化
微软windows11正式版GHOST ISO镜像 win11下载 国内最新版渠道下载
语言:中文版系统大小:5.31GB系统类型:Win11微软windows11正式版GHOST ISO镜像 win11下载 国内最新版渠道下载,微软2022年正式推出了win11系统,很多人迫不及待的要体验,本站提供了最新版的微软Windows11正式版系统下载,微软windows11正式版镜像 是一款功能超级强大的装机系统,是微软方面全新推出的装机系统,这款系统可以通过pe直接的完成安装,对此系统感兴趣,想要使用的用户们就快来下载
微软windows11系统下载 微软原版 Ghost win11 X64 正式版ISO镜像文件
语言:中文版系统大小:0MB系统类型:Win11微软Ghost win11 正式版镜像文件是一款由微软方面推出的优秀全新装机系统,这款系统的新功能非常多,用户们能够在这里体验到最富有人性化的设计等,且全新的柔软界面,看起来非常的舒服~微软Ghost win11 正式版镜像文件介绍:1、与各种硬件设备兼容。 更好地完成用户安装并有效地使用。2、稳定使用蓝屏,系统不再兼容,更能享受无缝的系统服务。3、为
雨林木风Windows11专业版 Ghost Win11官方正式版 (22H2) 系统下载
语言:中文版系统大小:4.75GB系统类型:雨林木风Windows11专业版 Ghost Win11官方正式版 (22H2) 系统下载在系统方面技术积累雄厚深耕多年,打造了国内重装系统行业的雨林木风品牌,其系统口碑得到许多人认可,积累了广大的用户群体,雨林木风是一款稳定流畅的系统,一直以来都以用户为中心,是由雨林木风团队推出的Windows11国内镜像版,基于国内用户的习惯,做了系统性能的优化,采用了新的系统
雨林木风win7旗舰版系统下载 win7 32位旗舰版 GHOST 免激活镜像ISO
语言:中文版系统大小:5.91GB系统类型:Win7雨林木风win7旗舰版系统下载 win7 32位旗舰版 GHOST 免激活镜像ISO在系统方面技术积累雄厚深耕多年,加固了系统安全策略,雨林木风win7旗舰版系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。win7 32位旗舰装机版 v2019 05能够帮助用户们进行系统的一键安装、快速装机等,系统中的内容全面,能够为广大用户
相关文章
- 轻简单松将QQ自带表情变大变小_腾讯QQ
- 音效灯效双绝,更有专属游戏优化 雷蛇 Razer 天狼星V2 2.1首发测评
- QQ视频聊天对方听不到我的声音的处理办法_腾讯QQ
- 教你如何一键重装系统win8
- 简述excel怎么求和
- Win10玩游戏全屏闪烁怎么办?
- 抖音怎么打开瘦脸功能?抖音瘦脸功能打开方法
- 微信语音发不了的原因与处理办法_微信
- win7内部版本7601此副本不是正版,本文教您怎样处理win7内部版本7601此副本不是正
- 注册Autodesk Revit 2016失败提示激活出错0015.111的问题
- win7宽带连接怎样创建,本文教您win7怎样创建宽带连接
- Win8系统打开mscomctl.ocx文件缺失加载失败怎么解决?
- 炫酷WIN8.1 酷比魔方 iWork 8仅售599元
- 微软发布 Win11 Build 23451 预览版更新:增强文件管理器和 Windows 聚焦等 - IT之家
- QQ运用技巧之QQ昵称敏感词汇如何输入_腾讯QQ
- WinXP更改开始菜单图标大小的步骤
- 深度技术ghost win7 32旗舰版介绍
- IFA2012:华硕展出Windows8平板Vivo Tab
热门系统
- 1华硕笔记本&台式机专用系统 GhostWin7 32位正式旗舰版2018年8月(32位)ISO镜像下载
- 2深度技术 Windows 10 x86 企业版 电脑城装机版2018年10月(32位) ISO镜像免费下载
- 3电脑公司 装机专用系统Windows10 x86喜迎国庆 企业版2020年10月(32位) ISO镜像快速下载
- 4雨林木风 Ghost Win7 SP1 装机版 2020年4月(32位) 提供下载
- 5深度技术 Windows 10 x86 企业版 六一节 电脑城装机版 版本1903 2022年6月(32位) ISO镜像免费下载
- 6深度技术 Windows 10 x64 企业版 电脑城装机版2021年1月(64位) 高速下载
- 7新萝卜家园电脑城专用系统 Windows10 x64 企业版2019年10月(64位) ISO镜像免费下载
- 8新萝卜家园 GhostWin7 SP1 最新电脑城极速装机版2018年8月(32位)ISO镜像下载
- 9电脑公司Ghost Win8.1 x32 精选纯净版2022年5月(免激活) ISO镜像高速下载
- 10新萝卜家园Ghost Win8.1 X32 最新纯净版2018年05(自动激活) ISO镜像免费下载
热门文章
常用系统
- 1新萝卜家园Ghost Win10 全新专业版X64 v2023.03最新免费下载
- 2电脑公司 GHOST WIN7 SP1 X64 稳定装机版 V2023.11 下载
- 3番茄花园 GHOST WIN10 X64 电脑城装机版 V2018.10 下载
- 4新萝卜家园 GhostWin7 SP1 最新电脑城极速装机版2018年8月(32位)ISO镜像下载
- 5新萝卜家园 Ghost Win7 x64 SP1 极速版2020年8月(64位) 高速下载
- 6Ghost win11 22563 测试版系统 v2023免费下载
- 7Win10 ghost纯净版2022下载_Win10 ghost纯净版64位系统镜像下载
- 8新萝卜家园Ghost Win8.1 X64位 纯净版2019年8月(自动激活) ISO镜像高费下载
- 9番茄花园GhostWin7 SP1电脑城六一节 极速装机版2021年6月(32位) 最新高速下载
- 10新萝卜家园电脑城专用系统 Windows10 x64 新春特别 企业版 版本1903 2022年2月(64位) ISO镜像免费下载