Multithreading 为什么下面的代码会产生死锁

Multithreading 为什么下面的代码会产生死锁,multithreading,go,channel,Multithreading,Go,Channel,我是哥朗新手。有人能解释一下为什么下面的代码会产生死锁吗 我知道将true发送到boolean您最初的死锁是由wg2.Add5造成的,您一直在等待5个goroutine完成,但只有一个goroutine完成了;你打电话给wg2,完成一次。将此更改为wg2.Add1,程序将无误运行 但是,我怀疑您打算使用通道中的所有值,而不是像您这样只使用一个值。如果将消费者功能更改为: func consumer2(c <-chan int) { defer wg2.Done() for

我是哥朗新手。有人能解释一下为什么下面的代码会产生死锁吗


我知道将true发送到boolean您最初的死锁是由wg2.Add5造成的,您一直在等待5个goroutine完成,但只有一个goroutine完成了;你打电话给wg2,完成一次。将此更改为wg2.Add1,程序将无误运行

但是,我怀疑您打算使用通道中的所有值,而不是像您这样只使用一个值。如果将消费者功能更改为:

func consumer2(c <-chan int) {
    defer wg2.Done()
    for i := range c {
        fmt.Printf("Consumer Got value %d\n", i)
    }
}
您将获得另一个死锁,因为通道在生产者函数中未关闭,消费者正在等待更多永远不会到达的值。将closec添加到producer函数将修复它。

为什么会出错? 运行代码时会出现以下错误:

➜  gochannel go run dl.go
Starting .... 1
Starting .... 2
Producer Writing to chan 0
Consumer Got value 0
Producer Writing to chan 1
fatal error: all goroutines are asleep - deadlock!
原因如下:

代码中有三个goroutine:main、producer2和consumer2。当它运行时

producer2向通道发送数字0 consumer2从通道接收到0,然后退出 producer2向通道发送1,但没有人在消费,因为consumer2已经退出 生产商2正在等待 main执行wg2.Wait,但并非所有waitgroup都已关闭。所以主要的是等待 两个goroutine在这里等待,什么也不做,无论你等待多久,什么也不会做。这是一个僵局!戈朗发现了它并惊慌失措

您在这里混淆了两个概念:

waitgourp的工作原理 如何从通道接收所有值 我将在这里简单地解释一下,互联网上有很多文章

waitgroup如何工作 WaitGroup是一种等待所有groutine完成的方法。在后台运行goroutines时,重要的是要知道它们何时全部退出,然后才能执行某些操作

在您的情况下,我们运行两个goroutine,因此在开始时我们应该设置wg2.Add2,并且每个goroutine应该添加wg2.Done以通知它已完成

从通道接收数据 从通道接收数据时。如果您确切知道它将发送多少数据,请按以下方式使用for循环:

for i:=0; i<N; i++ {
    data = <-c
    process(data)
}
for data := range c {
    process(data)
}
另外,当没有更多的数据要发送时,不要忘记关闭通道

如何修复它? 根据上述说明,代码可以固定为:

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg2 sync.WaitGroup

func producer2(c chan<- int) {
    defer wg2.Done()
    for i := 0; i < 5; i++ {
        time.Sleep(time.Second * 1)
        fmt.Printf("Producer Writing to chan %d\n", i)
        c <- i
    }
    close(c)
}

func consumer2(c <-chan int) {
    defer wg2.Done()
    for i := range c {
        fmt.Printf("Consumer Got value %d\n", i)
    }

}

func main() {
    c := make(chan int)
    wg2.Add(2)
    fmt.Println("Starting .... 1")
    go producer2(c)
    go consumer2(c)
    fmt.Println("Starting .... 2")

    wg2.Wait()
}

您向频道发送消息五次,但仅使用频道一次。producer2 goroutine将被阻止,直到四封邮件中的其余部分被使用。此外,您对sync.WaitGroup的使用是错误的,因为它调用Add5,但只调用一次完成。@ymonad我补充了我的理解。你能告诉我哪里出了问题吗?规则。Add5-我希望当使用者执行5次时,会调用5次Done。在步骤3中,您提到步骤2会再次重复,但事实并非如此,代码中的使用者只使用一次。
package main

import (
    "fmt"
    "sync"
    "time"
)

var wg2 sync.WaitGroup

func producer2(c chan<- int) {
    defer wg2.Done()
    for i := 0; i < 5; i++ {
        time.Sleep(time.Second * 1)
        fmt.Printf("Producer Writing to chan %d\n", i)
        c <- i
    }
    close(c)
}

func consumer2(c <-chan int) {
    defer wg2.Done()
    for i := range c {
        fmt.Printf("Consumer Got value %d\n", i)
    }

}

func main() {
    c := make(chan int)
    wg2.Add(2)
    fmt.Println("Starting .... 1")
    go producer2(c)
    go consumer2(c)
    fmt.Println("Starting .... 2")

    wg2.Wait()
}
➜  gochannel go run dl.go
Starting .... 1
Starting .... 2
Producer Writing to chan 0
Consumer Got value 0
Producer Writing to chan 1
Consumer Got value 1
Producer Writing to chan 2
Consumer Got value 2
Producer Writing to chan 3
Consumer Got value 3
Producer Writing to chan 4
Consumer Got value 4