首頁  >  文章  >  後端開發  >  使用 WaitGroups 和 Buffered Channels 的 Go 程式碼中出現死鎖的原因是什麼?

使用 WaitGroups 和 Buffered Channels 的 Go 程式碼中出現死鎖的原因是什麼?

PHPz
PHPz轉載
2024-02-09 11:09:30701瀏覽

使用 WaitGroups 和 Buffered Channels 的 Go 代码中出现死锁的原因是什么?

php小編百草在這篇文章中將解答一個常見問題:「使用WaitGroups 和Buffered Channels 的Go 程式碼中出現死鎖的原因是什麼?」在Go語言中,WaitGroups和Buffered Channels是常用的並發程式設計工具。然而,有時在使用它們的程式碼中可能會遇到死鎖的情況。本文將深入探討死鎖的原因,並提供解決方案,幫助讀者避免這種問題的發生。無論你是初學者還是有一定經驗的Go開發者,本文都將為你提供有價值的資訊。

問題內容

等待群組、緩衝通道和死鎖

我的這段程式碼會導致死鎖,但我不確定為什麼。我嘗試在幾個不同的地方使用互斥鎖,關閉單獨的 go 例程內外的通道,但結果仍然相同。

我嘗試透過一個通道 (inputchan) 發送數據,然後從另一個通道 (outputchan) 讀取資料

package main

import (
    "fmt"
    "sync"
)

func listStuff(wg *sync.WaitGroup, workerID int, inputChan chan int, outputChan chan int) {
    defer wg.Done()

    for i := range inputChan {
        fmt.Println("sending ", i)
        outputChan <- i
    }
}

func List(workers int) ([]int, error) {
    _output := make([]int, 0)

    inputChan := make(chan int, 1000)
    outputChan := make(chan int, 1000)

    var wg sync.WaitGroup
    wg.Add(workers)

    fmt.Printf("+++ Spinning up %v workers\n", workers)
    for i := 0; i < workers; i++ {
        go listStuff(&wg, i, inputChan, outputChan)
    }

    for i := 0; i < 3000; i++ {
        inputChan <- i
    }

    done := make(chan struct{})
    go func() {
        close(done)
        close(inputChan)
        close(outputChan)
        wg.Wait()
    }()

    for o := range outputChan {
        fmt.Println("reading from channel...")
        _output = append(_output, o)
    }

    <-done
    fmt.Printf("+++ output len: %v\n", len(_output))
    return _output, nil
}

func main() {
    List(5)
}

解決方法

主函數中的程式碼是連續的,首先嘗試將3k 值寫入inputchan 然後將從outputchan 讀取值。

您的程式碼會在第一個步驟中阻塞:

  • 在3k 值成功傳送到inputchan 之前,outputchan 不會流失任何內容,因此工作人員最終會在第一個1k 值之後卡在outputchan &lt ;- i
  • #一旦工作人員停止從 inputchan 中消耗資源,main 將在大約 2k 個值之後卡在 inputchan <- i
#

解決此問題的一種方法是讓生產者(inputchan <- i) 和最終消費者(for o := range outputchan {) 在單獨的goroutine中運行。

您可以將這些演員之一保留在主 goroutine 中,並為另一個演員旋轉新演員。例如:

go func(inputchan chan<- int){
    for i := 0; i < 3000; i++ {
        inputchan <- i
    }
    close(inputchan)
}(inputchan)

done := make(chan struct{})
go func() {
    close(done)
    // close(inputchan) // i chose to close inputchan above, don't close it twice
    close(outputchan)
    wg.wait()
}()

...

https://www.php.cn/link/80e4c54699b5b8cf8c67dd496909fceb

#一個額外的注意事項:圍繞發信號done 的操作順序很重要;通道doneoutputchan 只能在wg.done () 指示所有工作人員完成後關閉

// it is best to close inputChan next to the code that controls
    // when its input is complete.
    close(inputChan)
    // If you had several producers writing to the same channel, you
    // would probably have to add a separate waitgroup to handle closing,
    // much like you did for your workers

    go func() {
        wg.Wait()
        // the two following actions must happen *after* workers have
        // completed
        close(done)
        close(outputChan)
    }()

以上是使用 WaitGroups 和 Buffered Channels 的 Go 程式碼中出現死鎖的原因是什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除