在go并发编程中time包是比较常用的,比如执行一个需要在指定时间内完成的任务,可以使用time包结合通道来做,比如使用time包的定时器用来做超时等待。
//1
var timeout <-chan time.Time
func main() {
//2
timeout = time.After(time.Second * 3)
//3
fmt.Println(<-timeout)
}
如上代码1 声明了一个Time类型的通道,并且这个通道是单向的接受通道
代码2调用time.After给timeout变量初始化,time.After创建了一个定时器,这个定时器会在3秒后向通道timeout写入当前的时间,After函数的定义如下:
func After(d Duration) <-chan Time {
return NewTimer(d).C
}
可知其返回的是单向接受通道,这也是为何我们的timeout声明也是单向接受通道
代码3则从通道timeout中读取一个元素,运行上面代码会在3s后输出当前时间。
timer的定时器功能一般和select命令一块使用,用来检查任务执行是否超时了:
package main
import (
"fmt"
"time"
)
//1
var timeout <-chan time.Time
var result chan int
func main() {
//2
timeout = time.After(time.Second * 3)
result = make(chan int)
//3
go func() {
//3.1
fmt.Println("---begin do task---")
time.Sleep(time.Second * 1)
fmt.Println("---end do task---")
//3.2
result <- 1
}()
//4
select {
case e := <-result:
fmt.Printf("get result:%d", e)
case <-timeout:
fmt.Println("get result timeout")
}
}
如上代码1声明了了两个通道,其中timeout是一个Time类型的单向的接受通道,result是一个int类型的双向通道
代码2则使用time.After初始化timeout,这里是作用是等3s后向timeout写入当前时间,然后初始化了通道result.
代码3开启一个goroutine,其内部首先休眠几秒以模拟任务执行,休眠后代码3.2向通道result写入了一个元素1以模拟任务运行的结果
代码4使用select结构等待检查任务的状态,这里第一个case里面尝试从通道result获取任务执行的结果,第二个case尝试从timeout通道读取元素以便判断当前任务是否超时了;如果这两个case都没读取到元素则main goroutine会被阻塞,执行上面代码由于超时时间是3秒,而子goroutine休眠了1s,所以goroutine在休眠后向通道result写入了1,所以main groutine从第一个case中返回,然后打印get result:1。如果把子goroutine里面的休眠1s修改为5s,则会在3s后向timeout通道写入当前时间,这时候main goroutine会从第二个case返回,然后输出get result timeout
上面代码我们设置任务执行的超时时间为3s,如果任务在3s内执行完毕,则会打印出任务执行的结果;如果任务超过3秒还没执行完毕,则其就超时了,就打印出超时信息