Runtime: Golang 定时器实现原理及源码解析

定时器作为开发经常使用的一种数据类型,是每个开发者需要掌握的,对于一个高级开发很有必要了解它的实现原理,今天我们runtime源码来学习一下它的底层实现。

定时器分两种,分别为 Timer 和 Ticker,两者差不多,这里重点以Timer为例。

源文件位于 src/time/sleep.gosrc/time/tick.go 。 go version 1.16.2

数据结构

Timer 数据结构

// src/runtime/sleep.go

// The Timer type represents a single event.
// When the Timer expires, the current time will be sent on C,
// unless the Timer was created by AfterFunc.
// A Timer must be created with NewTimer or AfterFunc.
type Timer struct {
	C <-chan Time
	r runtimeTimer
}

Timer 数据类型是表示单个事件。当计时器过期时,当前的时候将会发送到 Timer.C 通道,如果用 AfterFunc 创建计时器的话,则例外。

对于计时器必须由 NewTimer()AfterFunc() 创建。

// Interface to timers implemented in package runtime.
// Must be in sync with ../runtime/time.go:/^type timer
type runtimeTimer struct {
	pp       uintptr
	when     int64
	period   int64
	f        func(interface{}, uintptr) // NOTE: must not be closure
	arg      interface{}
	seq      uintptr
	nextwhen int64
	status   uint32
}

字段说明

  • PP 当前对应的处理器P的指针
  • when 定时器被唤醒的时间
  • period 唤醒间隔时间,定时器为Timer数据类型时,此字段值为 0 时,否则为 Ticker 数据类型
  • f 唤醒后执行的函数,不能为 闭包匿名函数
  • arg 唤醒后执行的函数的参数
  • seq ?
  • nextwhen 当定时器状态为 timerModifiedEarliertimerModifiedLater 时,需要使用此字段值刷新为 when 字段
  • status 定时器状态

状态值常量有以下几个

Continue reading