GO 协程 为什么这样会造成死锁

package main

import (
    "fmt"
)

func f1(in chan int) {
    fmt.Println(<-in)
}

func main() {
    out := make(chan int)
    out <- 2
    go f1(out)
}

为什么这样会造成死锁?怎么解决?

阅读 7.2k
4 个回答

改成这样:

package main

import (
    "fmt"
)

func f1(in chan int) {

    fmt.Println(<-in)
}

func main() {

    out := make(chan int)
    go f1(out)
    out <- 2
}

因为你make是不带缓冲的chan
所以chan需要有人消费才能写入,不然会阻塞
因此还有第二种方法,生成带缓冲的chan:

make(chan int, 1)

out队列无缓冲,主线程会阻塞在这里。解决方法有两个。

第一,设置缓冲:

package main

import (
    "fmt"
)

func f1(in chan int) {
    fmt.Println(<-in)
}

func main() {
    out := make(chan int,1)
    out <- 2
    go f1(out)
}

第二,将go f1(out) 提前:

package main

import (
    "fmt"
)

func f1(in chan int) {
    fmt.Println(<-in)
}

func main() {
    out := make(chan int)
    go f1(out)
    out <- 2
}

无缓冲的 channel 收发都是阻塞的,你这里在 main goroutine 里面发了 2 ,那么就是一直被阻塞着不往下进行。

一直等待有人收,当然会死锁

需要明白2个概念,无缓冲通道和有缓存通道。

  1. ch := make(chan int)ch := make(chan int, 0)创建的都是无缓冲通道。
  2. ch := make(chan int, x),其中x>0,建立的是有缓存通道。

两者的区别是,无缓冲通道是同步的,写入数据时,必须有协程把数据读走才返回,有缓存通道是半异步的,当缓冲还没有用满时,写入数据时,只要缓存还有空余空间,写入到缓冲就可以返回。

题主这里是无缓冲通道,向out写数据时,协程f1还没有创建,也就无协程读out的数据,造成程序死锁。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏