问题的代码如下,在for select 循环中,本想通过 time.After 设置超时时间,但一直无法退出。
package main import ( "fmt" "math/rand" "time" ) func main() { ch := make(chan int) go func() { for v := range ch { fmt.Println(v) } }() END: for { select { case ch <- rand.Int(): case <-time.After(time.Second * 3): fmt.Println("timeout") break END } time.Sleep(time.Second) } }
控制台始终打印出从通道 ch 中读取的随机数,time.After 一直没能等到。
原因是每次进入到 case <-time.After(time.Second * 3): 时,都会创建一个新的通道返回,所以这个 case 每次都在等待接收新的通道的数据,永远不可能等到。
time.After 方法的源码如下:
func After(d Duration) <-chan Time { return NewTimer(d).C }
每次调用都会通过 NewTimer 创建一个新的 Timer,并且 Timer.C 也是新创建的通道。
func NewTimer(d Duration) *Timer { c := make(chan Time, 1) t := &Timer{ C: c, r: runtimeTimer{ when: when(d), f: sendTime, arg: c, }, } startTimer(&t.r) return t }
为了解决上面的问题,我们可以把 time.After 放在 for 循环外面,来解决此问题。
package main import ( "fmt" "math/rand" "time" ) func main() { ch := make(chan int) timer := time.After(time.Second * 3) go func() { for v := range ch { fmt.Println(v) } }() END: for { select { case ch <- rand.Int(): case <-timer: fmt.Println("timeout") break END } time.Sleep(time.Second) } }
版权声明:博主文章,可以不经博主允许随意转载,随意修改,知识是用来传播的。