Golang之select中time.After()为什么不生效
今天下午写bug的时候写了这样一个demo:
func test() error {
ticker := time.NewTicker(time.Millisecond * 10)
defer ticker.Stop()
for {
select {
case <- ticker.C: // case1: 执行这个
if ok() {
fmt.Println("done")
return nil
}
fmt.Println("continue")
case <- time.After(time.Millisecond * 100): // case2: 这个永远不会被执行到
return errors.New("time out")
}
}
}
func ok() bool {
t := rand.Intn(3)
if t == 0 {
return true
}
return false
}
渴望的逻辑是执行case1
数次之后如果一直不ok,就执行case2
超时退出。
结果多次测试发现case2
的time.After()
一直执行不到,上下求索之后得出结论如下:
每次执行
time.After()
都会创建一个新的timer
的channel,而select
语句是不可能记住它上次迭代的channel的。即case2
的time.After()
只在本次select
时有效,下次select
又重新从下次select
的time.Now()
开始计时了。(而且这种方式把一个异步操作变成了忙循环,违背了select语句的初衷。)
所以正确的操作应该是:
func test() error {
ticker := time.NewTicker(time.Millisecond * 10)
defer ticker.Stop()
timer := time.After(time.Millisecond * 100) // timer
for {
select {
case <- ticker.C:
if ok() {
fmt.Println("done")
return nil
}
fmt.Println("continue")
case <- timer: // 改这里
return errors.New("time out")
}
}
}
来源:
Each time you execute
time.After(4 * time.Second)
you create a new timer channel. There's no way theselect
statement can remember the channel it selected on in the previous iteration. You've also taken what was an asynchronous operation and turned it into a busy loop, defeating the purpose of theselect
statement.https://stackoverflow.com/questions/39212333/how-can-i-use-time-after-and-default-in-golang
注:
需要写明的是,并非所有select
中的time.After()
都不生效,只是针对类似这种select
有多个case
可选的情况。
posted on 2020-10-14 16:22 GaiheiluKamei 阅读(992) 评论(0) 编辑 收藏 举报