Go语言channel的阻塞问题
Hello,大家好,又见面了!上一遍我们将 channel 相关基础以及使用场景。这一篇,还需要再次进阶理解channel 阻塞问题。以下创建一个chan类型为int,cap 为3。 ch := make(chan string,1)
channel 内部其实是一个环形buf数据结构 ,是一种滑动窗口机制,当make完后,就分配在 Heap 上。
Channel 是如何发送数据和接收数据,会有什么问题出现,面试也是常见。 设 G1 为发送者:ch <- "hello"
上面,向 chan 发送一条"hello"数据: 第一步: acquire lock 第二步:enqueue(把"hello"拷贝buf数组里) 第三步:release lock
如果 G1 发送数据超过指定cap时,会出现什么情况?
看下面实例: ch := make(chan int,1) ch <- 100 ch <- 200
以上会出现什么,chan 缓冲区允许大小为1,如果再往chan仍数据,满了就会被阻塞,那么是如何实现阻塞的呢?当 chan 满时,会进入 gopark,此时 G1 进入一个 waiting 状态,然后会创建一个 sudog 对象,其实就sendq队列,把 200放进去。等 buf 不满的时候,再唤醒放入buf里面。
通过如下源码,你会更加清晰: type hchan struct { //省略部分代码… recvq waitq // list of recv waiters sendq waitq // list of send waiters //省略部分代码… } type waitq struct { first *sudog last *sudog } type sudog struct { g *g next *sudog prev *sudog elem unsafe.Pointer // data element (may point to stack) acquiretime int64 releasetime int64 ticket uint32 isSelect bool success bool parent *sudog // semaRoot binary tree waitlink *sudog // g.waiting list or semaRoot waittail *sudog // semaRoot c *hchan // channel }设 G2 为接收者:d := <- ch
上面,从 chan 获取数据: 第一步:也是先获取锁 第二步:从 buf 数据里面拷贝,赋给 d 变量 第三步:release lock
Go 语言核心思想:"Do not communicate by sharing memory; instead, share memory by communicating." 你可以看看这本书名叫:Effective Go
如果接收者,接收一个空对象,也会发生什么情况?
代码示例 : ch := make(chan int,1) t := <- ch
也会报错如下: fatal error: all goroutines are asleep - deadlock!
上面,从 chan 取出数据,可是没有数据了。此时,它会把 接收者 G2 阻塞掉,也是和G1发送者一样,也会执行 gopark 将状态改为 waiting,不一样的点就是。
正常情况下,接收者G2作为取出数据是去 buf 读取数据的,但现在,buf 为空了,此时,接收者G2会将sudog导出来,因为现在G2已经被阻塞了嘛,会把G2给G,然后将 t := <-ch 中变量 t 是在栈上的地址,放进去 elem ,也就是说,只存它的地址指针在sudog里面。
最后, ch <- 200 当G1往 chan 添加200这个数据,正常情况是将数据添加到buf里面,然后唤醒 G2 是吧,而现在是将 G1 的添加200数据直接干到刚才G2阻塞的t这里变量里面。
你会认为,这样真的可以吗?想一想,G2 本来就是已经阻塞了,然后我们直接这么干肯定没有什么毛病,而且效率提高了,不需要再次放入buf再取出,这个过程也是需要时间。不然,不得往chan添加数据需要加锁、拷贝、解锁一序列操作,那肯定就慢了,我想Go语言是为了高效及内存使用率的考虑这样设计的。(注意,一般都是在runtime里面完成,不然会出现象安全问题。)
总结 :
chan 类型的特点:chan 如果为空,receiver 接收数据的时候就会阻塞等待,直到 chan 被关闭或者有新的数据到来。有这种个机制,就可以实现 wait/notify 的设计模式。 使用 channel 要思考的问题?如果N个发送者发送到chan及N个接收者,这样会频繁导致锁频繁争用; 如果N个往 chan 发送,而 buf很小,会导致 Goroutine 不断被gopark,然后runtime开销就大了;
相关面试题: channel 有缓冲区和无缓冲区别? channel 线程安全吗? 是否了解 channel 底层实现,比如channel 底层数据结构?环形buf
你的每次「点赞+收藏+关注」是我创作最大动力。加油,奋斗永远都在路上!
如何使用BBEdit的正则表达式?作为搜索替換文本的强大工具,正则表达式(通常被称为Regex)可能会让初学者望而生畏一一好在有Bbedit。这款App的PatternPlayground(模式园地)功能可以让开发
云计算如何促进地铁行业发展?新网云资讯近年来随着城市圈的发展,全国各地都在加快推进城市轨道交通建设。缩短城市轨道交通建设周期提升运营效率简化运维管理的需求越来越突出,因此对城市轨道交通信息化也提出了更高效更节
三字母。cn域名市场火爆从未停歇新网域名资讯究竟是短域名更好,还是意义佳的域名更好,恐怕每个人心里都有自己的规范,或者说这两类都是好米。但短字母域名在记忆输入上都具备天然的优势,其含义的多样性,可以对应更多的终端
王者荣耀服务器异常崩溃,崩溃是什么造成的?新网云资讯王者荣耀一直都是国内手游市场的领军人物,自游戏上线至今王者荣耀的地位一直都是无可撼动的。昨日,王者荣耀的服务器却直接崩溃了,百万玩家被迫挂机,甚至登上了热搜榜第一的宝座。
云计算部署,为教育信息化按下加速键新网云资讯当今,全球数字经济蓬勃发展,各种新兴技术层出不穷,云计算便是其中之一。云计算服务从最初的兴起到逐渐落地到各个行业,经过了黄金发展的十年,一直保持着高速增长的趋势,被视为2
云计算如何帮助新零售行业发展?新网云资讯近几年,我们见证了身边太多新巨头的崛起,并且成长速度越来越快,尤其是新零售行业。和传统零售相比,新零售的革新是全面的。新零售不仅是对最终零售环节的升级,而且还将生产供应销
北京证券交易所成立,三字母域名BSE。cn被收入囊下新网域名资讯据国家企业信用信息公示系统官网消息,9月3日,北京证券交易所有限责任公司注册成立。继上海证券交易所深圳证券交易所之后,首都北京将迎来中国大陆第三个证交所。三家交易所形成
网站建设如何设计网站色调?新网建站资讯您的企业形象是您向全世界展示业务的方式。这就是世界如何看待您。从公司LOGO设计和名称,到字体和固定字体,您的公司色彩一直受到潜在消费者的关注。这就是为什么必须知道如何
两字母域名LA。com标价约3227万元出售新网域名资讯我们都知道,两字母。com域名全球仅有676枚,而且多数已经被企业建站或收藏,在市场流通极少,同时又具有庞大的升值空间和应用价值,投资它们可以让自己的资产增值数倍,所以
臻美外观让好声音看得见新一代HUAWEISoundX首发图赏新一代HUAWEISoundX正式亮相!作为首款搭载HarmonyOS2的高颜值音箱,新一代HUAWEISoundX在继承了好音质的基础上,再次在颜值上带来新突破,将高颜值和好音质
荣耀Magic3多主摄融合计算摄影技术上线手机镜头进入组团拍照时代2021年9月22日晚,荣耀正式发布多主摄融合计算摄影技术,荣耀Magic3系列将首发搭载。很多朋友好奇这究竟是项什么技术?究竟能够给手机影像带来什么改变?作为一名科技自媒体,同时