golang中的定时器 timer and ticker

本文介绍Go语言中定时器(timer)与循环定时器(ticker)的使用方法及原理,包括如何创建、读取、停止及重置定时器,并通过实例展示了如何利用定时器进行超时控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

睡眠
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++
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值