首頁 >後端開發 >Golang >為什麼 `sync.WaitGroup` 和 Channel 組合會導致 Go 中的死鎖?

為什麼 `sync.WaitGroup` 和 Channel 組合會導致 Go 中的死鎖?

Susan Sarandon
Susan Sarandon原創
2024-10-30 17:43:021004瀏覽

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