channel死锁问题

来源:11-2 使用Channel等待任务结束

KimZing

2018-03-25

func channelPrint(id int, ch chan int, done chan bool) {
   for {
      fmt.Printf("worker %d recevied %c \n", id, <- ch)
      //done <- true
      go func() {done <- true}()
   }
}

func channelArrayDemo() {
   var channels [10]chan int
   var dones [10]chan bool

   for i, _ := range channels {
      channels[i] = make(chan int)
      dones[i] = make(chan bool)
      go channelPrint(i, channels[i], dones[i])
   }

   for i, _ := range channels  {
      channels[i] <- 'a' + i
   }

   for i, _ := range channels {
      channels[i] <- 'A' + i
   }

   //for i,_ := range dones {
   //   <- dones[i]
   //   <- dones[i]
   //}
   
   //wait for all goroutine
   time.Sleep(5 * time.Second)
}

老师,您好,关于代码中`done <- true`改为`go func() {done <- true}()`就能避免死锁不是完全理解,虽然新开了协程来向done中放入bool,但是如果下面的两个`<-dones[i]`还没有执行到的话就应该报错。为了实验,我注释掉了`<-dones[i]`之后,仍然正常。想了很久没想通,麻烦老师解惑下,谢谢

一开始猜测会不会和闭包的机制类似,写了一个简短的Demo,运行同样通过,打印了in这个channel的指针,发现是同一个,还是没有搞明白。

import (
   "fmt"
   "time"
)

func send(in chan int) {
   fmt.Println(in)//一样的
   in <- 10
}

func main() {
   in := make(chan int)
   go send(in)
   go send(in)

   time.Sleep(time.Second)
   fmt.Println(<-in)
   fmt.Println(<-in)
}


写回答

3回答

Gundy

2018-04-08

http://tb.am/cpbtj  阿里云ECS,1 核 2 G 1 M 带宽 40 G SSD 硬盘,3 年 279 元,需要的抓紧上车啦


0
0

sd1700092

2018-04-08

楼主,其实我还是没明白,为什么`done <- true`改为`go func() {done <- true}()`就能避免死锁?

看了你自己给自己的回答,我表示仍然不解……

采用并行的方式往同一个channel里发数据,就能避免死锁。而采用串行的方式往同一个channel里发数据,就能发生死锁。

这个道理是何在呢?

0
0

KimZing

提问者

2018-03-26

终于想明白了,写了下面两个demo

第一个:

func recieve(ch chan int) {
   time.Sleep(time.Second)
   fmt.Printf("接收到:%d \n" , <-ch)
   fmt.Printf("接收到:%d \n" , <-ch)
   for {
      fmt.Print()
   }
}

func main() {
   ch := make(chan int)
   go recieve(ch)
   ch <- 1
   fmt.Println("1发送完毕")
   ch <- 2
   fmt.Println("2发送完毕")
   ch <- 3
   fmt.Println("3发送完毕")

}

输出:
1发送完毕
接收到:1 
接收到:2 
2发送完毕

没有打印『3发送完毕』,说明在ch <- 3这一行阻塞了。


然后写了另外一个demo
var ch = make(chan int)

func send(ch chan int) {
   ch <- 12
   fmt.Println("i am waiting for println 12")
   ch <- 13
   fmt.Println("i am waiting for println 13")
}

func main() {
   go send(ch)
   time.Sleep(5 * time.Second)
}

程序没有任何输出。程序中没有接收者,在"ch <- 12"这一行就已经阻塞了,
并没有执行到"ch <- 13"。
0
0

Google资深工程师深度讲解Go语言 由浅入深掌握Go语言

语法+分布式爬虫实战 为转型工程师量身打造

5995 学习 · 1909 问题

查看课程