首页  >  文章  >  后端开发  >  为什么 `sync.WaitGroup` 和 Channel 组合会导致 Go 中的死锁?

为什么 `sync.WaitGroup` 和 Channel 组合会导致 Go 中的死锁?

Susan Sarandon
Susan Sarandon原创
2024-10-30 17:43:02929浏览

Why Does a `sync.WaitGroup` and Channel Combination Lead to a Deadlock in Go?

了解在 Go 中使用sync.WaitGroup 和 Channel 时的死锁

开发人员在使用sync.WaitGroup 时经常会遇到 Go 应用程序永远不会退出的问题和渠道。本文探讨了此类死锁背后的原因,并提供了使用 WaitGroup 的解决方案。

考虑提供的示例代码:

package main

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "sync"
)

var symbols = []string{
    "ASSA-B.ST",
    "ELUX-B.ST",
    "HM-B.ST",
}

func main() {

    fmt.Println("fetching quotes...")

    fetchedSymbols := make(chan string)
    var wg sync.WaitGroup
    wg.Add(len(symbols))

    for _, symbol := range symbols {
        go fetchSymbol(symbol, &wg, fetchedSymbols)
    }

    for response := range fetchedSymbols {
        fmt.Println("fetched " + response)
    }

    wg.Wait()

    fmt.Println("done")

}

func fetchSymbol(symbol string, wg *sync.WaitGroup, c chan<- string) {
    defer wg.Done()
    resp, err := http.Get("http://ichart.yahoo.com/table.csv?s=" + symbol + "&amp;a=0&amp;b=1&amp;c=2000")
    defer resp.Body.Close()

    if err != nil {
        log.Fatal(err)
    }

    out, err := os.Create("./stock-quotes/" + symbol + ".csv")
    defer out.Close()

    if err != nil {
        log.Fatal(err)
    }

    io.Copy(out, resp.Body)
    c <- symbol
}

在此代码中,fetchedSymbols 上的范围循环将阻塞 main无限期地发挥作用。为什么?因为 fetchedSymbols 通道永远不会关闭。为了解决这个死锁,可以使用 WaitGroup 来发出何时关闭通道的信号:

...
go func() {
    wg.Wait()
    close(fetchedSymbols)
}()

for response := range fetchedSymbols {
    fmt.Println("fetched " + response)
}

...

由于 WaitGroup 已经跟踪所有 goroutine 何时完成,因此可以利用它来触发 fetchedSymbols 通道的关闭,确保范围循环正常终止。

以上是为什么 `sync.WaitGroup` 和 Channel 组合会导致 Go 中的死锁?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn