php小編子墨將為大家介紹如何保證取消上下文會導致goroutine終止的方法。當我們在使用goroutine時,有時需要在某個條件滿足時取消它,以避免不必要的計算和資源浪費。為了確保goroutine能夠正確終止,我們可以使用context套件提供的機制。 context包提供了一種在goroutine之間傳遞請求的方法,並且可以在需要時取消這些請求。透過合理地使用context包,我們可以確保goroutine在取消上下文時能夠正確地終止,從而避免資源洩漏和其他潛在的問題。下面我們將詳細介紹如何使用context套件來實現這一目標。
假設發生下列情況:
我們有下面的 consumer
函數,在 goroutine 中運行。
另一個 goroutine 正在 intchan
通道上毫無延遲地發送整數。換句話說,在 for 迴圈的每次迭代中,intchan
上都有一個準備好接收的值。
啟動 consumer
goroutine 的 goroutine 已取消傳遞到 consumer
的上下文。因此,ctx.done()
通道也有一個可供接收的值。
問題:
select
將隨機選擇一種情況,因為兩者都已準備好運行。 select
不會繼續選擇 <- intchan
案例?如果<- cx.done()
案例在for 迴圈的每次迭代中都準備就緒,我們如何知道<- ctsx.done()
案例最終會被選中? func consumer(ctx context.context, intchan chan int) { for { select { case <-ctx.done(): return case i := <-intchan: foo(i) } } }
我嘗試在下面的程式中使用 consumer
函數。
在該程式的多次運行中,consumer
和 producer
goroutine 似乎總是終止。
為什麼我們最終不會以 <-ctx.done()
案例從未執行的運行結束?
package main import ( "context" "fmt" "sync" "time" ) func main() { ctx, cancelFunc := context.WithCancel(context.Background()) var wg sync.WaitGroup wg.Add(2) // add 2, because we spawn 2 goroutines Producer(ctx, &wg) fmt.Println(time.Now()) time.Sleep(time.Second * 5) // cancel the context after 5 seconds cancelFunc() fmt.Println("CANCELLED") wg.Wait() // wait till both producer and consumer goroutines terminate fmt.Println(time.Now()) } func Producer(ctx context.Context, wg *sync.WaitGroup) { intChan := make(chan int) go Consumer(ctx, intChan, wg) go func() { defer wg.Done() for { select { case <-ctx.Done(): return case intChan <- 1: } } }() } func Consumer(ctx context.Context, intChan chan int, wg *sync.WaitGroup) { defer wg.Done() for { select { case <-ctx.Done(): return case _ = <-intChan: } } }
沒有任何保證。保證終止的最簡單方法是在 select 語句之外使用 ctx.err()
檢查錯誤。將錯誤返回傳遞上下文的程式碼也很常見。我會這樣寫 consumer 函數:
func Consumer(ctx context.Context, intChan chan int) error { for ctx.Err() == nil { select { case <-ctx.Done(): case i := <-intChan: foo(i) } } return ctx.Err() }
以上是我們如何保證取消的上下文會導致 goroutine 終止?的詳細內容。更多資訊請關注PHP中文網其他相關文章!