1 回答
TA贡献1866条经验 获得超5个赞
前言:使用time.Timer
是推荐的方式,time.After()
这里的使用只是为了演示和推理。请使用第二种方法。
使用time.After()
(不推荐这样做)
如果你放入time.After()
case 分支,那将在每次迭代中“重置”,因为每次都会返回一个新频道,这样就可以了:
func doingSomething(listenCh <-chan string) {
for {
select {
case mystr := <-listenCh:
log.Println("Received", mystr)
case <-time.After(1 * time.Second):
log.Println("Timeout")
return
}
}
}
(我在 Go Playground 上使用 1 秒超时来提高可测试性。)
我们可以这样测试它:
ch := make(chan string)
go func() {
for i := 0; i < 3; i++ {
ch <- fmt.Sprint(i)
time.Sleep(500 * time.Millisecond)
}
}()
doingSomething(ch)
输出(在Go Playground上尝试):
2009/11/10 23:00:00 Received 0
2009/11/10 23:00:00 Received 1
2009/11/10 23:00:01 Received 2
2009/11/10 23:00:02 Timeout
使用time.Timer
(推荐方案)
如果从通道接收的速率很高,这可能会有点浪费资源,因为在后台创建并使用了一个新计时器,time.After()
它不会神奇地停止并在不再需要时立即收集垃圾如果您在超时前从通道收到一个值。
time.Timer
一个对资源更友好的解决方案是在循环之前创建一个循环,如果在超时之前收到一个值,则将其重置。
这就是它的样子:
func doingSomething(listenCh <-chan string) {
d := 1 * time.Second
t := time.NewTimer(d)
for {
select {
case mystr := <-listenCh:
log.Println("Received", mystr)
if !t.Stop() {
<-t.C
}
t.Reset(d)
case <-t.C:
log.Println("Timeout")
return
}
}
}
测试和输出是一样的。在Go Playground试试这个。
- 1 回答
- 0 关注
- 113 浏览
添加回答
举报