从频道阅读一定时间的惯用方法



我需要从 Go 通道读取数据一段时间(比如 5 秒)。带有超时的 select 语句对我不起作用,因为我需要读取尽可能多的可用值并在 5 秒后停止。到目前为止,我已经提出了一个使用额外时间通道的解决方案 https://play.golang.org/p/yev9CcvzRIL

package main
import "time"
import "fmt"
func main() {
// I have no control over dataChan
dataChan := make(chan string)
// this is a stub to demonstrate some data coming from dataChan
go func() {
for {
dataChan <- "some data"
time.Sleep(time.Second)
}
}()
// the following is the code I'm asking about
timeChan := time.NewTimer(time.Second * 5).C
for {
select {
case d := <-dataChan:
fmt.Println("Got:", d)
case <-timeChan:
fmt.Println("Time's up!")
return
}
}
}

我想知道是否有更好或更惯用的方法来解决这个问题?

差不多就是这样。但是,如果您不需要停止或重置计时器,只需使用time.After()而不是time.NewTimer().time.After()"相当于NewTimer(d)。C"。

afterCh := time.After(5 * time.Second)
for {
select {
case d := <-dataChan:
fmt.Println("Got:", d)
case <-afterCh:
fmt.Println("Time's up!")
return
}
}

或者(根据您的喜好),您可以在for语句中声明 after 通道,如下所示:

for afterCh := time.After(5 * time.Second); ; {
select {
case d := <-dataChan:
fmt.Println("Got:", d)
case <-afterCh:
fmt.Println("Time's up!")
return
}
}

我也知道这只是一个例子,但总是想一想你开始的goroutine将如何正确结束,因为在你的情况下,产生数据的goroutine永远不会终止。

另外不要忘记,如果可以在不阻止的情况下执行多个案例,则会随机选择一个。因此,如果dataChan已准备好从"不间断"接收,则无法保证循环将在超时后立即终止。在实践中,这通常不是问题(从甚至超时也不能保证开始,请参阅长度为 0 的 Golang 计时器的详细信息),但您不应该在"任务关键"应用程序中忘记它。有关详细信息,请参阅相关问题:

强制优先级 Go 选择语句

golang:当涉及多个渠道时,选择是如何工作的?

看起来带有截止日期的上下文很合适,例如

func main() {
dataChan := make(chan string)
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
defer cancel()
go func(ctx context.Context) {
for {
select {
case dataChan <- "some data":
time.Sleep(time.Second)
case <-ctx.Done():
fmt.Println(ctx.Err())
close(dataChan)
return
}
}
}(ctx)
for d := range dataChan {
fmt.Println("Got:", d)
}
}

相关内容

  • 没有找到相关文章

最新更新