使用 Channel 覆盖 Goroutine 中的超时
在 Golang 中,当使用 Goroutines 和 Channel 执行异步任务时,可以指定超时以确保操作不会无限期地挂起。然而,在某些场景下,超时情况可能不会按预期执行。
考虑以下代码片段:
package main import ( "fmt" "time" ) func main() { c1 := make(chan int, 1) // Buffered channel with capacity 1 go func() { for { time.Sleep(1500 * time.Millisecond) // Sleep for 1.5 seconds c1 <- 10 // Send value to channel } }() go func() { for { select { case i := <-c1: fmt.Println(i) case <-time.After(2000 * time.Millisecond): fmt.Println("TIMEOUT") // Not executed } } }() fmt.Scanln() // Wait for user input }
在这段代码中,我们有两个 goroutine:一个定期发送一个值发送到缓冲通道 c1,另一个值从 c1 中选择,超时时间为 2 秒。但是,超时情况(“TIMEOUT”)永远不会被打印。
其原因在于缓冲通道的性质以及超时的处理方式。在这种情况下,向 c1 发送值的 goroutine 将每隔 1.5 秒不断地重新填充通道。因此,第二个 goroutine 中的 select 语句总是会在超时到期之前从 c1 接收到一个值。
为了解决这个问题并确保超时情况被执行,我们需要在外部创建超时通道选择循环。这样可以防止每次从 c1 接收到值时都将其丢弃:
timeout := time.After(2000 * time.Millisecond) // Create timeout channel only once for { select { case i := <-c1: fmt.Println(i) case <-timeout: fmt.Println("TIMEOUT") } }
通过此修改,select 语句将继续从 c1 中选择,但如果在指定超时内没有接收到值,则“TIMEOUT”情况将被执行。
以上是如何使用 Go 中的通道可靠地覆盖 Goroutine 超时?的详细内容。更多信息请关注PHP中文网其他相关文章!