英文源地址
对于连接到外部资源或需要限制执行时间的程序来说, 超时非常重要.由于channel和select的存在,在Go中实现超时是简单而优雅的.
package main
import (
"fmt"
"time"
)
func main() {
// 对于我们的示例, 假设我们正在执行一个外部调用, 该调用在2s之后返回通道c1上的结果.
// 注意, 通道是有缓冲的, 因此在程序中的发送是非阻塞的.
// 这是一种常见的模式, 用于防止从未读取通道的情况下发生goroutine泄漏
c1 := make(chan string, 1)
go func() {
time.Sleep(2 * time.Second)
c1 <- "result 1"
}()
// 这是实现超时的select.
// res := <c1异步等待结果,<-time.After异步等待一个值在一秒的超时后发送.
// 因为select会在第一个接收者就绪的情况下执行, 所以如果操作花费的时间超过允许的1秒后, 我们将采用超时的情况
select {
case res := <-c1:
fmt.Println(res)
case <-time.After(time.Second):
fmt.Println("timeout 1")
}
// 如果我们允许更长的3秒超时时间, 那么将成功接收来自c2的结果, 将打印结果
c2 := make(chan string, 1)
go func() {
time.Sleep(2 * time.Second)
c2 <- "result 2"
}()
select {
case res := <-c2:
fmt.Println(res)
case <-time.After(3 * time.Second):
fmt.Println("timeout 2")
}
}
运行此程序显示第一个操作超时, 第二个操作成功.
╰─ time go run ./main.go ─╯
timeout 1
result 2
go run ./main.go 0.19s user 0.09s system 8% cpu 3.237 total
下一节将介绍: 非阻塞通道操作