当前位置: 代码迷 >> 综合 >> golang中的定时器 timer and ticker
  详细解决方案

golang中的定时器 timer and ticker

热度:48   发布时间:2023-12-09 10:39:34.0
睡眠
var d = 5*time.Second
time.Sleep(d)
定时器 timer
func NewTimer(d Duration) *Timer {
    c := make(chan Time, 1)t := &Timer{
    C: c,r: runtimeTimer{
    when: when(d),f:    sendTime,arg:  c,},}startTimer(&t.r)return t
}func sendTime(c interface{
    }, seq uintptr) {
    // Non-blocking send of time on c.// Used in NewTimer, it cannot block anyway (buffer).// Used in NewTicker, dropping sends on the floor is// the desired behavior when the reader gets behind,// because the sends are periodic.select {
    case c.(chan Time) <- Now():default:}
}

timer 的运行机制是,当达到结束时间了,就会调用 f 函数,也就是 sendTime 函数,此函数会向 c 通道中写入当前时间,c 通道是一个长度为 1 的缓存通道,因此写入通道并不会阻塞。

读取 timer.C 通道。

tr := time.NewTimer(d)
fmt.Println(<-tr.C)

提前终止定时器

func (t *Timer) Stop() bool

重新设置定时器

func (t *Timer) Reset(d Duration) bool
timer 的应用:超时控制
func After(d Duration) <-chan Time {
    return NewTimer(d).C
}

After的使用:

c := time.After(d)
ti := <-c
fmt.Println(ti)

After实现超时控制

ch1 := make(chan int)
go func() {
    time.Sleep(10 * time.Second)ch1 <- 1
}()select {
    
case <-ch1:fmt.Println("get msg")
case <-time.After(d):fmt.Println("timeout")
}

这是一种同步阻塞的方式来实现的超时控制。

还有一种异步的方式来控制超时。

ch1 := make(chan int)
ch2 := make(chan int)
time.AfterFunc(d, func() {
    ch2<-1
})go func() {
    time.Sleep(10 * time.Second)ch1 <- 1
}()select {
    
case <-ch1:fmt.Println("get msg")
case <-ch2:fmt.Println("timeout")
}

来看看 AfterFunc 的实现:

// AfterFunc waits for the duration to elapse and then calls f
// in its own goroutine. It returns a Timer that can
// be used to cancel the call using its Stop method.
func AfterFunc(d Duration, f func()) *Timer {
    t := &Timer{
    r: runtimeTimer{
    when: when(d),f:    goFunc,arg:  f,},}startTimer(&t.r)return t
}func goFunc(arg interface{
    }, seq uintptr) {
    go arg.(func())()
}

时间结束后会开启一个 goroutine 来运行 f 函数。

context包中的WithTimeout()就是使用的AfterFunc。

循环定时器 ticker
func NewTicker(d Duration) *Ticker {
    if d <= 0 {
    panic(errors.New("non-positive interval for NewTicker"))}// Give the channel a 1-element time buffer.// If the client falls behind while reading, we drop ticks// on the floor until the client catches up.c := make(chan Time, 1)t := &Ticker{
    C: c,r: runtimeTimer{
    when:   when(d),period: int64(d),f:      sendTime,arg:    c,},}startTimer(&t.r)return t
}

也是使用的通道来实现的通知。

for c := range time.NewTicker(d).C {
    fmt.Println(c)
}// 或者for c := range time.Tick(d) {
    fmt.Println(c)
}

带条件终止ticker

tick := time.NewTicker(d)
n := 1
for c := range tick.C {
    fmt.Println(c)if n >= 3 {
    tick.Stop()return}n++
}
  相关解决方案