Go(Golang)_09_定时器

@TOC

定时器

time/sleep.go中runtimeTimer的结构体定义:

type runtimeTimer struct {
    pp       uintptr
    when     int64              // 当前定时器下次被触发的绝对时间
    period   int64              // 当前定时器周期性触发间隔(Timer的为0)
    f        func(any, uintptr) // 定时器触发时执行的回调函数(仅接收arg和seq两个参数)

    arg      any     // 回调函数的参数1
    seq      uintptr // 回调函数的参数2
                     // Timer不使用该参数,且仅在网络收发场景下使用)
    nextwhen int64
    status   uint32
}

1)runtimeTimer由goroutine对应的P进行维护;

2)每创建个Timer/Ticker就等于创建个runtimeTimer;

3)runtimeTimer存在数组中,并根据when字段进行堆排序;


Timer

一次性定时器(Timer):经历指定时间后触发事件(自动关闭)

1)常配合select实现程序的超时和程序的延迟执行;



创建Timer的格式(引入time包):Timer对象 := time.NewTimer(时间)

1)Timer创建后立刻开始计时(无须其他启动命令);

2)Timer创建后会交由本goroutine对应的P进行维护;

3)Timer对象在指定时间会向自身的C通道发送当时的系统时间;


常用方法/函数:

1)停止Timer的计时(并不会关闭通道C)
func (t *Timer) Stop() bool
// 若t已被关闭或过期则返回false(成功返回true)

2)重置Timer的计时为d
func (t *Timer) Reset(d Duration) bool
// 可激活已被停止或过期的Timer
// 若t已被关闭或过期则返回false(成功返回true)

3)创建匿名Timer,仅返回匿名Timer的通道C
func After(d Duration) <-chan Time
// 匿名Timer无法被关闭(慎用)

4)创建Timer,并在过期后调用函数f
func AfterFunc(d Duration, f func() ) *Timer
// 函数f是异步执行的(主goroutine需设置时间等待)
// 可通过返回Timer的Stop()方法取消等待和对函数f的调用

实现原理

time/sleep.go中Timer的结构体定义:

type Timer struct {
    C <-chan Time  // 应用于用户
    r runtimeTimer // 应用于底层定时器
}

time/sleep.go中NewTimer()函数的定义:

func NewTimer(d Duration) *Timer {
	c := make(chan Time, 1)   // 创建管道

    t := &Timer{              // 初始化Timer(根据runtimeTimer)
        C: c,                 // 赋值管道
        r: runtimeTimer{
            when: when(d),    // 指定触发的绝对时间
            f:    sendTime,   // 触发后执行sendTime函数
            arg:  c,          // sendTime的参数
        },
    }

    startTimer(&t.r) // 启动定时器(将runtimeTimer交由P进行维护)
    return t
}

1)创建缓冲区为1的管道,使senTime()函数永不阻塞;



time/sleep.go中sendTime()函数的定义:

func sendTime(c interface{}, seq uintptr) {
    select {
    case c.(chan Time) <- Now():
    default:
    }
}

1)select搭配的空defalut分支,使sendTime()函数永不阻塞;

2)若多次触发相同Timer且管道中还有值,会导致后续触发事件遗失;


Ticker

周期性定时器(Ticker):周期性触发事件(手动关闭)

1)配合for-range和select分别实现程序的循环定时任务和聚合任务;


创建Ticker的格式(引入time包):Ticker对象 := time.NewTicker(时间)

1)Ticker创建后立刻开始计时(无须其他启动命令);

2)Ticker创建后会交由本goroutine对应的P进行维护;

3)Ticker对象在指定时间会向自身的C通道发送当时的系统时间;

4)创建Ticker对象后应使用defer和其Stop()方法确保其被关闭;

//Ticker未被关闭会导致资源泄露(其不会自动关闭)



常用方法/函数:

1)停止Ticker对象
func (t *Ticker) Stop()
// 不会关闭通道C(通道C会在数据被读取完后,自动关闭)

2)创建匿名Ticker,仅返回匿名Ticker的通道C
func (d Duration) <-chan Time
// 该Ticker无法被关闭(慎用)

实现原理

time/tick.go中Ticker的结构体定义:

type Ticker struct {
    C <-chan Time  // 应用于用户
    r runtimeTimer // 应用于底层定时器
}

time/tick.go中NewTicker()函数的定义:

func NewTicker(d Duration) *Ticker {
    if d <= 0 {
        panic(errors.New("non-positive interval for NewTicker"))
    }
    c := make(chan Time, 1)
    t := &Ticker{
        C: c,
        r: runtimeTimer{
            when:   when(d),
            period: int64(d),   // Timer与Ticker的唯一不同之处
            f:      sendTime,
            arg:    c,
        },
    }

    startTimer(&t.r)
    return t
}

1)Ticker创建后不可修改其周期;

2)Ticker使用完毕后务必主动调用其Stop()方法(配合defer语句);


time/tick.go中sendTime()函数的定义:

func sendTime(c interface{}, seq uintptr) {
    select {
    case c.(chan Time) <- Now():
    default:
    }
}

1)select搭配的空defalut分支,使sendTime()函数永不阻塞;

2)若多次触发相同Timer且管道中还有值,会导致后续触发事件遗失;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值