Go阻塞通道的一个小坑

0x01 问题

阻塞类型chan就是使用make时,只指定一个类型,不指定长度,或者长度指定为0。

它有如下要求:

  • 发送方和接受方都准备好时,才能工作。

所以想到了如下场景:

发送方和使用方都使用select非阻塞方式,会有什么现象?

即如下代码:是否会有输出?

package main

import "fmt"
import "time"

func main() {
        c := make(chan int)

        go func() {
                for {
                        select {
                        case a := <-c:
                                fmt.Println(a)
                        default:
                        }
                }
        }()
        go func() {
                for {
                        select {
                        case c <- 1:
                                fmt.Println("sended")
                        default:
                        }
                }
        }()

        for {
                time.Sleep(100)
        }
}

实验结果大家可能吃了一惊,居然没有任何输出。

0x02 解释

这个问题也问题也容易解析。非阻塞通道要求,双方都准备好了,才能工作。示例代码中,两个协程 都是在尝试下,发现不行,就走了。所以,刚好某个时刻两者同时尝试了,一方才能发送成功,一方才能收到。

想象AB两个人在打电话。拨一下就挂,别外一方要刚好在点接听键,才能打过去。

  1. A拨一下,没接哦,那我挂了,再拨一下。。。
  2. B点一下接听,没打,哦那算了,我再点一下接听。。。

两个人就这样一直在折腾,电话却一直没打通。。。

整个实现虽然是在研究(play with)通道,但因为Go语言也没有限制这样用法,Go运行时有检查死锁,这种场景也不属于死锁,所以真实场景可能有人会写出这样的代码。那就会有大问题了。

0x03 小结

这个起源也是出于对Go原理的好奇,经过实验发现这里确实有坑。希望小伙伴们不要踩到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值