首頁 >後端開發 >Golang >停止無限期寫入通道的 goroutine

停止無限期寫入通道的 goroutine

WBOY
WBOY轉載
2024-02-05 23:09:07939瀏覽

停止无限期写入通道的 goroutine

問題內容

我有一個函數可以建立一個無限期填充通道的 goroutine,例如:

func foo() <-chan int {
  ch := make(chan int) 
  go func() {
    defer close(ch)
    for {
      ch <- 1
    } 
  }() 
  return ch
}

假設我們有一個消費者想在一段時間後停止:

ch:=foo() 
<-ch
<-ch
// done

現在我想清理 goroutine 資源,包括通道。我嘗試為此添加一個“完成”通道,但隨後我遇到了僵局:

func Foo() (<-chan int, chan<- bool) {
  ch := make(chan int)
  done := make(chan bool)
  go func() {
    defer close(ch)
    for {
      select {
      case <-done:
          return
      default:
          ch <- 1
      }
    } 
  }() 
  return ch, done
}

func main() {
  ch, done := Foo()
  <-ch
  <-ch
  done <- true
  // HERE
}

現在,它似乎可以工作,但這只是因為程式退出,如果我用一些io操作替換// here(例如:http.get(「http://google. com”)) ,我面臨死鎖(fatal 錯誤:所有goroutine 都在睡覺- 死鎖!)。 我想知道是否有另一種方法可以清理由 foo 函數創建的生成的 goroutine 和通道。


正確答案


只需在啟動的 goroutine 中將 default 替換為 case 即可:

func Foo() (<-chan int, chan<- bool) {
  ch := make(chan int)
  done := make(chan bool)
  go func() {
    defer close(ch)
    for {
      select {
      case <-done:
          return
      case ch <- 1:
      }
    } 
  }() 
  return ch, done
}

原始程式碼在default情況下出現死鎖的原因如下:

  • 當沒有其他並發運行的 goroutine 寫入 done 通道時,啟動的寫入 ch 通道的 goroutines 會立即轉到 default 情況。然後 goroutine 會阻塞在 ch <- 1 行,直到其他 goroutine 從 ch 讀取值。
  • 主協程從 ch 讀取兩次。這會導致在啟動的 goroutine 處有兩個成功的執行循環。然後它嘗試寫入 done。此時啟動的goroutine可能已經檢查了select語句,陷入default情況並阻塞在ch <- 1行。因此主 goroutine 也會無限期地阻塞在 done <- true 行。這會導致僵局。

以上是停止無限期寫入通道的 goroutine的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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