將sync.WaitGroup與外部函數結合使用的最佳實踐
在處理Go中的並發時,有效利用至關重要。本文解決了將等待群組作為參數傳遞給外部函數時出現的常見問題。
問題:
考慮以下程式碼:
<code class="go">package main import ( "fmt" "sync" ) func main() { ch := make(chan int) var wg sync.WaitGroup wg.Add(2) go Print(ch, wg) // go func(){ for i := 1; i <= 11; i++ { ch <- i } close(ch) defer wg.Done() }() wg.Wait() //deadlock here } // Print prints all numbers sent on the channel. // The function returns when the channel is closed. func Print(ch <-chan int, wg sync.WaitGroup) { for n := range ch { // reads from channel until it's closed fmt.Println(n) } defer wg.Done() }</code>
這段程式碼中,在指定行發生死鎖,導致程式只印從1到10,而不是到達11。此錯誤源自於將sync.WaitGroup的副本傳遞給Print方法,這阻礙了對其 Done 方法的預期呼叫。
解決方案1:
要解決此問題,請將指標傳遞給等待群組:
<code class="go">package main import ( "fmt" "sync" ) func main() { ch := make(chan int) var wg sync.WaitGroup wg.Add(2) go Print(ch, &wg) go func() { for i := 1; i <= 11; i++ { ch <- i } close(ch) defer wg.Done() }() wg.Wait() //deadlock here } func Print(ch <-chan int, wg *sync.WaitGroup) { for n := range ch { // reads from channel until it's closed fmt.Println(n) } defer wg.Done() }</code>
傳遞wg 的位址可以確保Print 方法呼叫main 函數中等待的等待群組上的Done 方法。
解決方案2:簡化的Print 方法
或者,可以透過刪除WaitGroup 參數來簡化Print 方法,因為它不需要了解任何等待操作:
<code class="go">package main import ( "fmt" ) func main() { ch := make(chan int) go func() { for i := 1; i <= 11; i++ { ch <- i } close(ch) }() for n := range ch { // reads from channel until it's closed fmt.Println(n) } } </code>
在這種情況下,主goroutine 直接接收通道並列印它的值不涉及等待群組。這種方法保留了所需的功能,並消除了 Print 方法中對 WaitGroup 管理的需求。
結論:
當將sync.WaitGroup 作為參數傳遞給外部函數時,確保函數接收到正在等待的等待組的正確引用至關重要。重構函數以直接處理等待群組或傳遞指標到等待群組可以有效防止死鎖錯誤並確保正確的並發控制。
以上是在 Go 中使用帶有外部函數的sync.WaitGroup時如何避免死鎖?的詳細內容。更多資訊請關注PHP中文網其他相關文章!