在Go語言中如何限制協程數量并避免死鎖問題?

在Go語言中如何限制協程數量并避免死鎖問題?

go語言協程并發控制與死鎖避免詳解

在Go語言中,利用goroutine實現并發任務處理時,常常需要限制協程數量以防止資源耗盡。然而,不當的限制機制可能導致死鎖。本文將探討如何在限制協程數量的同時,有效避免死鎖,并確保從協程中順利接收數據。

問題描述:

使用sync.WaitGroup和通道c來限制同時運行的協程數量,但將數據發送到另一個通道creport時,出現死鎖錯誤:“fatal Error: all goroutines are asleep – deadlock!”。

立即學習go語言免費學習筆記(深入)”;

錯誤代碼示例(簡化版):

(原文提供的代碼示例存在邏輯錯誤,此處提供一個更清晰的簡化版,以便說明問題和解決方案)

package main  import (     "fmt"     "sync" )  func worker(id int, c chan struct{}, creport chan int) {     c <- struct{}{} // 獲取令牌,進入處理     defer func() { <-c }() // 釋放令牌,離開處理      // 模擬任務處理     result := id * 2     creport <- result  }  func main() {     c := make(chan struct{}, 3) // 限制同時運行3個協程     creport := make(chan int)     var wg sync.WaitGroup      for i := 0; i < 10; i++ {         wg.Add(1)         go func(i int) {             defer wg.Done()             worker(i, c, creport)         }(i)     }      wg.Wait() // 等待所有協程完成     close(creport) // 關閉creport通道,防止死鎖      for result := range creport {         fmt.Println("Result:", result)     } } 

死鎖原因分析:

此例中,creport通道未被關閉,main函數中的for…range creport語句試圖從一個未關閉的通道中讀取數據。如果所有worker goroutine都已完成,但main函數仍在等待creport通道中的數據,就會發生死鎖。

解決方案:

為了避免死鎖,必須在所有worker goroutine完成任務后,關閉creport通道。 wg.Wait()確保所有協程都已完成,之后再關閉creport。 修改后的代碼如下:

package main  import (     "fmt"     "sync" )  // ... (worker function remains the same) ...  func main() {     // ... (channel creation remains the same) ...      for i := 0; i < 10; i++ {         wg.Add(1)         go func(i int) {             defer wg.Done()             worker(i, c, creport)         }(i)     }      wg.Wait() // 等待所有協程完成     close(creport) // 關閉creport通道      for result := range creport {         fmt.Println("Result:", result)     } }

通過在wg.Wait()之后關閉creport通道,for…range creport循環能夠正常結束,避免了死鎖。 這確保了所有數據都被正確接收,并且不會發生死鎖。 記住,正確地管理通道的關閉對于避免Go語言中的死鎖至關重要。

? 版權聲明
THE END
喜歡就支持一下吧
點贊10 分享