golang中time.After一直无法跳出select循环
<p>问题的代码如下,在for select 循环中,本想通过 time.After 设置超时时间,但一直无法退出。</p><pre>
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)
}
}
</pre>
<p>控制台始终打印出从通道 ch 中读取的随机数,time.After 一直没能等到。</p>
<p>原因是每次进入到 case <-time.After(time.Second * 3): 时,都会创建一个新的通道返回,所以这个 case 每次都在等待接收新的通道的数据,永远不可能等到。</p>
<p>time.After 方法的源码如下:</p>
<pre>
func After(d Duration) <-chan Time {
return NewTimer(d).C
}
</pre>
<p>每次调用都会通过 NewTimer 创建一个新的 Timer,并且 Timer.C 也是新创建的通道。</p>
<pre>
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
}
</pre>
<p>为了解决上面的问题,我们可以把 time.After 放在 for 循环外面,来解决此问题。</p>
<pre>
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)
}
}</pre>
<p>源文地址:https://www.cnblogs.com/jkko123/p/12733487.html</p>
页:
[1]