如何優雅地停止Go 例程
在Go 中,goroutines 提供輕量級並發,但優雅地終止它們可能具有挑戰性。這個問題解決了向 Goroutine 發送信號以停止其執行的需要。
提供的程式碼示範了透過將布林標誌 (tooLate) 設為 true 來嘗試停止 Goroutine。然而,這種方法是有問題的,因為從通道讀取資料會阻塞 goroutine。
解決方案 1:使用附加通道
此解決方案涉及使用第二個通道(太晚了)傳達停止訊號。即使 goroutine 沒有主動讀取該通道,該通道仍保持開啟。
<code class="go">func main() { tooLate := make(chan struct{}) // Unbuffered channel for stop signal proCh := make(chan string) go func() { for { fmt.Println("working") time.Sleep(1 * time.Second) select { case <-tooLate: fmt.Println("stopped") return case proCh <- "processed": // Non-blocking send default: // Allows the goroutine to continue without blocking } fmt.Println("done here") } }() select { case proc := <-proCh: fmt.Println(proc) case <-time.After(1 * time.Second): fmt.Println("too late") close(tooLate) // Signal to goroutine to stop } time.Sleep(4 * time.Second) fmt.Println("finish\n") }</code>
在此解決方案中,當時間限製到期時,tooLate 通道將關閉,這會導致 goroutine 退出其阻塞 select 語句並返回。
解決方案 2:使用sync.Cond
或者,您可以使用sync.Cond 類型來實現更複雜的訊號機制。下面是一個範例:
<code class="go">func main() { var stopped bool cond := sync.NewCond(new(sync.Mutex)) go func() { for { cond.L.Lock() defer cond.L.Unlock() if stopped { fmt.Println("stopped") return } fmt.Println("working") cond.Wait() // Wait for the signal to stop } }() time.Sleep(1 * time.Second) cond.Signal() // Send the stop signal time.Sleep(4 * time.Second) fmt.Println("finish\n") }</code>
透過這個方法,goroutine 會等待 cond.Wait() 方法,直到收到 cond.Signal() 的訊號。
以上是如何優雅地停止 Go 例程:避免死鎖和無回應進程的指南?的詳細內容。更多資訊請關注PHP中文網其他相關文章!