在 go
中,我们很容易就可以实现超时控制,今天分享2种解决方案:
- 1.select + time.After
- 2.select + context
其实两种方案中,我们都是通过 channel
来控制的,在方案1中,对于 time.After
, 通过返回一个只读 <- chan Time
实现,而 context
中,则通过 context.Done()
实现,通过返回 <- chan struct{}
信号实现,
下面看看函数签名:
time.After
可以看到,只需要传入一个时间的duration即可。
// go1.19/src/time/sleep.go
func After(d Duration) <-chan Time {
return NewTimer(d).C
}
context.Done
这其实是通过实现 context
接口的 timeCtx
。
接下来看看超时控制的相关代码实现。
1.select + time.After
package main
import (
"context"
"fmt"
"time"
)
func main() {
fmt.Printf("[%s] start...\n", time.Now().Format(time.RFC3339))
taskCh := make(chan int)
go func() {
time.Sleep(5*time.Second)
taskCh <- 1
}()
select {
case data := <- taskCh:
fmt.Println(data)
case <- time.After(time.Second):
fmt.Println("timeout!")
}
fmt.Printf("[%s] end...\n", time.Now().Format(time.RFC3339))
}
我们通过实现一个耗时的task
实现任务耗时,在time.After
中传入1s的超时,到1s时,该case
先收到信号,从而结束整个执行。
2.select + context
package main
import (
"context"
"fmt"
"time"
)
func main() {
fmt.Printf("[%s] start...\n", time.Now().Format(time.RFC3339))
ctx, cancel := context.WithTimeout(context.Background(), 3 * time.Second)
defer cancel()
taskCh := make(chan int)
go func() {
time.Sleep(5*time.Second)
taskCh <- 1
}()
select {
case data := <- taskCh:
fmt.Println(data)
case <- ctx.Done():
fmt.Println("timeout!")
}
fmt.Printf("[%s] end...\n", time.Now().Format(time.RFC3339))
}
类似于上一个方案,我们只是在context
中传入3s的超时时长,到了时间后,就会收到 ctx.Done()
,进而结束执行。