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

停止無限期寫入通道的 goroutine

WBOY
發布: 2024-02-05 23:09:07
轉載
900 人瀏覽過

停止无限期写入通道的 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
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!