首頁 > 後端開發 > Golang > 主體

為什麼提供的帶有 WaitGroup 和緩衝通道的 Go 代碼會導致死鎖?

Barbara Streisand
發布: 2024-10-26 22:08:02
原創
680 人瀏覽過

Why does the provided Go code with WaitGroup and buffered channel result in a deadlock?

Go 中使用WaitGroup 和緩衝通道的死鎖

Go 中,當多個goroutine 互相等待完成時會發生死鎖,導致陷入僵局。當錯誤地使用緩衝通道和 WaitGroups 時,可能會發生這種情況。

考慮以下程式碼:

<code class="go">package main

import "fmt"
import "sync"

func main() {
    ch := make(chan []int, 4)
    var m []int

    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            ch <- m
            return
        }()
    }
    wg.Wait()

    for c := range ch {
        fmt.Printf("c is %v", c)
    }
}</code>
登入後複製

此程式碼預計會建立一個緩衝區大小為 4 的通道並啟動 5 個 goroutine ,每個都會向通道發送一個空切片。主協程等待所有協程完成,然後在通道上進行範圍。

但是,此程式碼將導致死鎖。為什麼?

死鎖原因:

程式碼中存在兩個問題:

  1. 通道容量:通道的容量為4,這表示它最多可以容納4 個元素。然而,有 5 個 Goroutine 試圖發送到 Channel,導致最後一個 Goroutine 會阻塞等待一個 slot 被釋放。
  2. 關閉 Channel:range ch 循環繼續等待元素進入頻道。由於沒有更多的 goroutine 可以寫入通道,循環將無限期地等待。

解:

  1. 增加通道容量:透過將通道容量增加到5,將有足夠的插槽供所有goroutine 發送它們的值而不會阻塞。此外,在 goroutine 完成寫入後關閉通道將向範圍循環發出信號,表明不再有元素到來,從而防止它無限期地等待。

    <code class="go">ch := make(chan []int, 5)
    ...
    wg.Wait()
    close(ch)</code>
    登入後複製
  2. 使用Done Loop 中的(): 可以使用WaitGroup 的Done() 方法在最後一個goroutine 完成時發出訊號,而不是關閉通道。透過在 range 循環中呼叫 Done(),當通道為空且循環可以退出時,主 goroutine 將收到通知。

    <code class="go">go func() {
        for c := range ch {
            fmt.Printf("c is %v\n", c)
            wg.Done()
        }
    }()
    wg.Wait()</code>
    登入後複製

這些解決方案透過確保以下方式解決了死鎖:通道有足夠的容量,並且當沒有更多元素可以從通道讀取時,範圍循環退出。

以上是為什麼提供的帶有 WaitGroup 和緩衝通道的 Go 代碼會導致死鎖?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!