本文介绍了为什么在同一个 goroutine 中使用无缓冲通道会导致死锁?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我确信对这种微不足道的情况有一个简单的解释,但我是 go 并发模型的新手.

I'm sure that there is a simple explanation to this trivial situation, but I'm new to the go concurrency model.

当我运行这个例子时

package main

import "fmt"

func main() {
    c := make(chan int)
    c <- 1
    fmt.Println(<-c)
}

我收到此错误:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /home/tarrsalah/src/go/src/github.com/tarrsalah/tour.golang.org/65.go:8 +0x52
exit status 2

为什么?

c <- 包裹在 goroutine 中使示例按预期运行

Wrapping c <- in a goroutine makes the example run as we expected

package main

import "fmt"

func main() {
    c := make(chan int)
    go func(){
       c <- 1
    }()
    fmt.Println(<-c)
}

再说一遍,为什么?

拜托,我需要深入的解释,而不仅仅是如何消除死锁和修复代码.

Please, I need deep explanation , not just how to eliminate the deadlock and fix the code.

推荐答案

来自文档 :

如果通道未缓冲,则发送方会阻塞,直到接收方收到该值.如果通道有缓冲区,则发送方只会阻塞直到值已复制到缓冲区;如果缓冲区已满,这意味着等待直到某个接收者检索到一个值.

另有说法:

  • 当一个通道已满时,发送者等待另一个 goroutine 通过接收来腾出空间
  • 你可以看到一个无缓冲的通道总是满的:必须有另一个 goroutine 来接收发送者发送的内容.

这一行

c <- 1

阻塞,因为通道没有缓冲.由于没有其他goroutine来接收值,这种情况无法解决,这是一个死锁.

blocks because the channel is unbuffered. As there's no other goroutine to receive the value, the situation can't resolve, this is a deadlock.

您可以通过将频道创建更改为不阻塞

You can make it not blocking by changing the channel creation to

c := make(chan int, 1)

以便在频道中的一个项目被阻塞之前有空间.

so that there's room for one item in the channel before it blocks.

但这不是并发的意义所在.通常,您不会在没有其他 goroutine 的情况下使用通道来处理您放入的内容.你可以像这样定义一个接收 goroutine :

But that's not what concurrency is about. Normally, you wouldn't use a channel without other goroutines to handle what you put inside. You could define a receiving goroutine like this :

func main() {
    c := make(chan int)
    go func() {
        fmt.Println("received:", <-c)
    }()
    c <- 1
}

演示

这篇关于为什么在同一个 goroutine 中使用无缓冲通道会导致死锁?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-07 03:55