新手问题 为何报死锁?

codesky · 2020年01月19日 · 最后由 chenqinghe 回复于 2020年01月19日 · 70 次阅读

package main

import (
"fmt"
"time"
)

func main(){
report()


time.Sleep(time.Duration(30)*time.Second)
fmt.Println("done")
}


func report(){
ch1 := make(chan interface{})

ch2 := make(chan interface{})

go func() {
report1(ch1)
report2(ch2)

close(ch1)
close(ch2)
}()

for c1 := range ch1{
fmt.Println(c1)
}
for c2 := range ch2{
fmt.Println(c2)
}

//go func() {
// for c1 := range ch1{
// fmt.Println(c1)
// }
//}()
//
//go func() {
// for c2 := range ch2{
// fmt.Println(c2)
// }
//}()

defer func() {
e := recover()
if e != nil{
fmt.Println("fuck error")
}
}()

}

func report1(ch1 chan<- interface{}){
fmt.Println("report1 start")
ch1 <- "abc_1"
fmt.Println("report1 done")
}


func report2(ch2 chan<- interface{}){
fmt.Println("report2 start")
ch2 <- "abc_2"
fmt.Println("report2 done")
}


以上代码为何报死锁呢?换成注释部分的代码就可以,哪里有知识黑洞。


更多原创文章干货分享,请关注公众号
  • 加微信实战群请加微信(注明:实战群):gocnio

<p>for ... range... 可以遍历 channel 直到 channel 被关闭并且 channel 里的数据被全部消费完。</p><p>上面代码 report1 是可以很快执行完毕返回的,但是 report2 没有 receiver,ch2 不能被消费,所以一直阻塞,因此 ch1 和 ch2 就不能被关闭。</p><p>下面两个 range 循环,因为 channel 没有被关闭,所以第一个循环不会结束,一直阻塞在那,于是第二个 range 不能被执行,所以上面的 report2 一直无法退出。</p><p>所以造成了死锁。</p><p>而注释的代码中,两个 range 循环分别在两个 goroutine 中,一个阻塞不会影响另一个,所以两个 report 都可以迅速返回,然后 channel 被 close,range 循环退出。</p>

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册