Golang 定时器底层实现深度剖析
本文将基于 Golang 源码对 Timer 的底层实现进行深度剖析。主要包含以下内容:
- Timer 和 Ticker 在 Golang 中的底层实现细节,包括数据结构等选型。
- 分析
time.Sleep的实现细节,Golang 如何实现 Goroutine 的休眠。
注:本文基于 go-1.13 源码进行分析,而在 go 的 1.14 版本中,关于定时器的实现略有一些改变,以后会再专门写一篇文章进行分析。
概述
我们在日常开发中会经常用到 time.NewTicker 或者 time.NewTimer 进行定时或者延时的处理逻辑。
Timer 和 Ticker 在底层的实现基本一致,本文将主要基于 Timer 进行探讨研究。Timer 的使用方法如下:
1 | import ( |
在上面的例子中,我们首先利用 time.NewTimer 构造了一个 2 秒的定时器,同时使用 <-timer.C 阻塞等待定时器的触发。
Timer 的底层实现
对于 time.NewTimer 函数,我们可以轻易地在 go 源码中找到它的实现,其代码位置在 time/sleep.go#L82。如下:
1 | func NewTimer(d Duration) *Timer { |
NewTimer 主要包含两步:
- 创建一个 Timer 对象,主要包括其中的
C属性和r属性。r属性是runtimeTimer类型。 - 调用
startTimer函数,启动 timer。
在 Timer 结构体中的属性 C 不难理解,从最开始的例子就可以看到,它是一个用来接收 Timer 触发消息的 channel。注意,这个 channel 是一个有缓冲 channel,缓冲区大小为 1。
我们主要看的是 runtimeTimer 这个结构体:
when: when 代表 timer 触发的绝对时间。计算方式就是当前时间加上延时时间。f: f 则是 timer 触发时,调用的 callback。而arg就是传给 f 的参数。在 Ticker 和 Timer 中,f 都是 sendTime。
timer 对象构造好后,接下来就调用了 startTimer 函数,从名字来看,就是启动 timer。具体里面做了哪些事情呢?
startTimer 具体的函数定义在 runtime/time.go 中,里面实际上直接调用了另外一个函数 addTimer...
剩余内容已隐藏