在 Go 中使用超時和通道
Goroutines 和通道為 Go 中的並發編程提供了強大的機制。然而,處理 goroutine 中的超時可能會很棘手。
在您想要使用 goroutine 和超時檢查 URL 清單的可及性的場景中,可能存在超時不會被執行的情況,即使一些 URL 無法存取。
讓我們來分析一下提供的程式碼:
func check(u string) bool { time.Sleep(4 * time.Second) return true } func IsReachable(urls []string) bool { ch := make(chan bool, 1) for _, url := range urls { go func(u string) { select { case ch <- check(u): case <-time.After(time.Second): ch <- false } }(url) } return <-ch }
問題出在 check 函數。當你在 goroutine 中使用 time.Sleep 時,它會暫停目前的 goroutine,在這個例子中是運行 check 函數的 goroutine。當 check 函數暫停時,外層 goroutine 中的 select 語句仍會嘗試執行。
在這種情況下,select 語句的兩個分支(檢查結果或逾時)將在 4 年後執行檢查返回時的秒數。然而,由於兩個分支都是可運行的,運行時可以選擇執行其中一個,這可能會導致始終返回 true。
要解決這個問題,您需要為每個檢查函數建立一個新的goroutine,如下所示更正後的程式碼如下:
func check(u string, checked chan<- bool) { time.Sleep(4 * time.Second) checked <- true } func IsReachable(urls []string) bool { ch := make(chan bool, 1) for _, url := range urls { go func(u string) { checked := make(chan bool) go check(u, checked) select { case ret := <-checked: ch <- ret case <-time.After(time.Second): ch <- false } }(url) } return <-ch }
這種情況下,check函數是在一個單獨的goroutine中執行的,確保它不會暫停外層goroutine,並且超時可以正確執行。
以上是如何在帶有通道的 Go Goroutine 中正確實現逾時?的詳細內容。更多資訊請關注PHP中文網其他相關文章!