我有一個函數可以建立一個無限期填充通道的 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
情況下出現死鎖的原因如下:
done
通道時,啟動的寫入 ch
通道的 goroutines 會立即轉到 default
情況。然後 goroutine 會阻塞在 ch <- 1
行,直到其他 goroutine 從 ch
讀取值。 ch
讀取兩次。這會導致在啟動的 goroutine 處有兩個成功的執行循環。然後它嘗試寫入 done
。此時啟動的goroutine可能已經檢查了select
語句,陷入default
情況並阻塞在ch <- 1
行。因此主 goroutine 也會無限期地阻塞在 done <- true
行。這會導致僵局。 以上是停止無限期寫入通道的 goroutine的詳細內容。更多資訊請關注PHP中文網其他相關文章!