Go Channels: Why Timeouts Remain Unexecuted
Consider a scenario where goroutines and channels are employed like in the code snippet below. Why does the timeout scenario never materialize?
func main() { c1 := make(chan int, 1) go func() { for { time.Sleep(1500 * time.Millisecond) c1 <- 10 } }() go func() { for { select { case i := <-c1: fmt.Println(i) case <-time.After(2000 * time.Millisecond): fmt.Println("TIMEOUT") // Not Executed } } }() fmt.Scanln() }
Analysis
The timeout scenario does not occur because a goroutine continuously sends values to the c1 channel roughly every 1.5 seconds. The timeout would only become effective if no values were received from c1 for 2 seconds.
However, upon receiving a value from c1, a new time.After call is made in the subsequent select execution, generating a fresh channel where a value will only be issued after another 2 seconds. The timeout channel from the previous select execution is discarded, rendering it ineffective.
Solution
To address this issue, the timeout channel should be created only once, effectively:
timeout := time.After(2000 * time.Millisecond) for { select { case i := <-c1: fmt.Println(i) case <-timeout: fmt.Println("TIMEOUT") // Will be printed after 2 seconds } }
Output
The modified code subsequently prints:
10 TIMEOUT 10 10 10 ...
Hence, the timeout scenario is now successfully executed after 2 seconds, mirroring the intended behavior.
The above is the detailed content of Go Channels: Why Doesn't My Timeout in a `select` Statement Ever Trigger?. For more information, please follow other related articles on the PHP Chinese website!