了解在 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 + "&a=0&b=1&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中文网其他相关文章!