【我不信你没有这样的疑惑】浅谈Go语言的通道状态——正常、阻塞、panic、死锁

浅谈Go语言的通道状态——正常、阻塞、panic、死锁

关于通道,在未初始化、关闭、正常状态下的情况,对其进行读写会出现哪些情况的总结

项目未初始化关闭的通道
关闭操作panicpanic
发送操作死锁panic
接收操作死锁通道缓冲区为空(无缓冲通道视为空),则一直读取0值;否则正常读取
项目正常情况(未关闭)
关闭操作正常关闭
发送操作阻塞或者正常发送
接收操作阻塞或者正常接收

来看下面的例子,先别看答案:

//以下程序会不会死锁
func main() {
	ch := make(chan int)
	go func() {
		select {
		case <-ch:
		}
	}()
	time.Sleep(1000 * time.Second)  //①
}
//以下程序会不会死锁
func main() {
	ch := make(chan int)
	go func() {
		select {
		case <-ch:
		}
	}()
	select {}   //②
}

前一个程序会不会死锁,后一个程序会死锁

我们再来看一个例子:

//以下程序会不会死锁
func main() {
	ch := make(chan int)
	go func() {
		select {
		case <-ch:
		}
	}()

	for {   //③
		select {
			case <-time.After(time.Second):   
			fmt.Println(1)
		}
	}
}

不会死锁
这三个例子是为什么呢?为什么单单一个select{},就直接给程序干成了死锁?
妈的,我也不知道怎么解释
第一个例子,虽然程序是sleep在那里,但是本质上Go语言底层也一直在检测是否睡够了时间,说的直白一点就是,此时main函数中,有程序正在执行,并不是什么都没有执行。
第三个例子,其实道理和第一个例子的道理是一样的,就是main中,虽然ch这里一直在阻塞,不过没关系,还有其他的协程(此时是主协程)还在执行就行,也就是说,只要协程没有全部都阻塞就行

再来一个例子,来对比第二个例子

func main() {
	ch := make(chan int)
	cht := make(chan int)
	go func() {
		select {
		case <-ch:
		}
	}()

	for {
		select {
		case <-cht:
			// ....
		}
	}
}

这个例子,毫无疑问,肯定是直接死锁
这个例子其实和第二个例子是一个道理,第二个例子就单单只有一个select{},其实就相当于这个例子,虽然有一个通道cht,但是也是一直阻塞的状态。然而此时呢,main中的所有协程处于全部阻塞的状态,所以直接死锁。

总结:

困扰我很久的问题,这下终于明白了。
在程序没错误(不是由于通道关闭引发的)情况下,在mian函数中,无论启动多少个协程,只要有一个协程是未阻塞的状态,程序就不会死锁;只要main中,全部的协程(包括主协程)都处于阻塞的状态,那么程序就会死锁。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

秋山刀名鱼丶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值