0

有人可以解释为什么这段代码会引发“致命错误:所有 goroutines 都在休眠 - 死锁!”?

我似乎无法找到问题所在。我已经看到一些关于这个特定错误的问题,但原因主要是循环通过一个通道而不关闭它。谢谢!

package main

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

func main() {

    ch := make(chan time.Duration)

    var wg sync.WaitGroup

    for _, v := range []time.Duration{5, 1} {
        wg.Add(1)
        go wait(v, ch, wg)
        fmt.Println(<-ch)
    }

    wg.Wait()
}

func wait(seconds time.Duration, c chan time.Duration, wg sync.WaitGroup) {

    defer wg.Done()

    time.Sleep(seconds * time.Second)

    c <- seconds
}
4

1 回答 1

4

您必须WaitGroup通过引用而不是按值传递。否则Done没有效果。这种类型的文档说:

首次使用后不得复制 WaitGroup。

将您的代码修复为此,它将起作用:

func main() {

    ch := make(chan time.Duration)

    var wg sync.WaitGroup

    for _, v := range []time.Duration{5, 1} {
        wg.Add(1)
        go wait(v, ch, &wg)
        fmt.Println(<-ch)
    }

    wg.Wait()
}

func wait(seconds time.Duration, c chan time.Duration, wg *sync.WaitGroup) {

    defer wg.Done()

    time.Sleep(seconds * time.Second)

    c <- seconds
}

这种模式也很常见,如下所示:

func main() {
    ch := make(chan time.Duration)

    var wg sync.WaitGroup

    for _, v := range []time.Duration{5, 1} {
        wg.Add(1)

        go func() {
            defer wg.Done()
            wait(v, ch)
        }()
        fmt.Println(<-ch)
    }

    wg.Wait()
}

func wait(seconds time.Duration, c chan time.Duration) {
    time.Sleep(seconds * time.Second)
    c <- seconds
}

这种情况的好处是wait不必知道任何等待组(例如,它可能是第 3 方函数),并且通过值或引用传递等待组没有混淆。

于 2021-06-24T18:18:01.097 回答