Go中使用单调时钟获得准确的时间间隔问题
作者:幽鬼 发布时间:2024-05-22 10:14:19
墙上时钟与单调时钟
墙上时钟
墙上时钟也称为墙上时间。大多是1970年1月1日(UTC)以来的秒数和毫秒数。
墙上时间可以和NTP(Network Time Protocal,网络时间协议)同步,但是如果本地时钟远远快于NTP服务器,则强制重置之后会跳到先前某个时间点。(这里不是很确定,猜测是如果时间差的不多,则调整石英晶体振荡器的频率,慢慢一致。如果差很多,则强行一致)
单调时钟
机器大多有自己的石英晶体振荡器,并将其作为计时器。单调时钟的绝对值没有任何意义,根据操作系统和语言的不同,单调时钟可能在程序开始时设为0、或在计算机启动后设为0等等。但是通过比较同一台计算机上两次单调时钟的差,可以获得相对准确的时间间隔。
Time的结构
type Time struct {
// wall and ext encode the wall time seconds, wall time nanoseconds,
// and optional monotonic clock reading in nanoseconds.
//
// From high to low bit position, wall encodes a 1-bit flag (hasMonotonic),
// a 33-bit seconds field, and a 30-bit wall time nanoseconds field.
// The nanoseconds field is in the range [0, 999999999].
// If the hasMonotonic bit is 0, then the 33-bit field must be zero
// and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext.
// If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit
// unsigned wall seconds since Jan 1 year 1885, and ext holds a
// signed 64-bit monotonic clock reading, nanoseconds since process start.
wall uint64
ext int64
...
}
wall和ext共同记录了时间,但是分为两种情况,一种是没有记录单调时钟(比如是通过字符串解析得到的时间),另一种是记录了单调时钟(比如通过Now)。
wall的第一位是一个标记位
如果为1,则表示记录了单调时钟。则wall的2-34(闭区间)位记录了从1885-1-1到现在的秒数,最后30位记录了纳秒数。而ext记录了从程序开始运行到现在经过的单调时钟数。
如果为0,则表示没有记录单调时钟。则wall的2-34(闭区间)位全部为0(那最后30位是啥?)。而ext记录了从1-1-1到现在经过的秒数。
Since的实现
这里比较关键的代码是第914行的 runtimeNano() - startNano
。 startNano
的含义还是直接上代码比较明了。
var startNano = 0
func init(){
startNano = runtimeNano()
}
runtimeNano()
是调用了汇编,获取了操作系统当前的单调时钟。前面说过,单调时钟的绝对值没有什么意义。因此这里将两个时间相减,得到了从程序开始到现在的单调时钟。
然后看一下Sub
func (t Time) Sub(u Time) Duration {
if t.wall&u.wall&hasMonotonic != 0 {
te := t.ext
ue := u.ext
d := Duration(te - ue)
if d < 0 && te > ue {
return maxDuration // t - u is positive out of range
}
if d > 0 && te < ue {
return minDuration // t - u is negative out of range
}
return d
}
d := Duration(t.sec()-u.sec())*Second + Duration(t.nsec()-u.nsec())
// Check for overflow or underflow.
switch {
case u.Add(d).Equal(t):
return d // d is correct
case t.Before(u):
return minDuration // t - u is negative out of range
default:
return maxDuration // t - u is positive out of range
}
}
这里我们只需要关注2-13行即可。除去了范围检查,这里的主要逻辑就是两个Time的ext相减。而ext又都代表了单调时钟,所以最后返回的是单调时钟的差值。
小结
在分布式系统中,我们经常需要判断时间间隔来检测心跳。而墙上时钟与NTP的组合可能会带来时间的前后跳跃与闪烁,所以使用单调时钟更加安全和保险。
在go语言中,没有直接调用调用时钟的函数。可以通过 time.Now()
获得带单调时钟的 Time
结构体,并通过Since和Until获得相对准确的时间间隔。
参考资料
go time分析:https://zhuanlan.zhihu.com/p/93299132
一个commit:https://link.zhihu.com/?target=https%3A//github.com/golang/go/commit/fc3f8d43f1b7da3ee3fb9a5181f2a86841620273
go1.14.2 源码
数据密集型应用系统设计(书)
来源:https://mp.weixin.qq.com/s?__biz=MzkyMTI5MTgzNg==&mid=2247484818&idx=1&sn=c965af56ed87d17b3b8b19ab503a1186&utm_source=tuicool&utm_medium=referral


猜你喜欢
- 本文实例讲述了python os模块简单应用。分享给大家供大家参考,具体如下:举例中的目录形式如下所示:In [36]: pwdOut[36
- 事情是这样的五一假期第一天值班隔壁有点喜欢的小姐姐突然跑过来跟我聊天“微信账号切换来切换去 特别麻烦”“怎么能同时打开多个呢?”我心想,你有
- asp分页做为一个经典的asp问题,有着非常丰富的分页形式和分页方法,但是大多数的asp分页都是使用VBscript作为服务器端的脚本,本文
- 本文实例讲述了JS实现动画兼容性的transition和transform方法。分享给大家供大家参考,具体如下:今天在开发纯手工js打造图片
- 前言最近工作中遇到一个需求,是根据用户连续记录天数来计算的,求出用户在一段时间内最大的连续记录时间,例如在 2016-01-01 和 201
- 前言:数据的排序是比较常用的操作,DataFrame 的排序分为两种,一种是对索引进行排序,另一种是对值进行排序,接下来就分别介绍一下。1.
- 1.主要功能如下:1.classification分类2.Regression回归3.Clustering聚类4.Dimensionalit
- 使用Python 分析Nginx access 日志,根据Nginx日志格式进行分割并存入MySQL数据库。一、Nginx access日志
- 很实用的过滤重复数据的asp代码,函数如下:<%'**************************************
- Demo里的三种方法:方法1是两层div,兼容FF3.1a+, Safari 3+, Chrome, IE6/7方法2是两层div,除了IE
- 引言 近期公司vue前端项目需求:实现弹窗的拖拽,四边拉伸及对角线拉伸,以及弹窗边界处理
- 本篇文章主要介绍了python OpenCV学习笔记之绘制直方图的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来
- 目录Python 数据化运营1、内容介绍2、一般应用场景3、聚类的常见方法4、Keans聚类实现5、聚类的评估指标6、聚类效果可视化7、数据
- 1.sorted函数按key值对字典排序先来基本介绍一下sorted函数,sorted(iterable,key,reverse),sort
- 本文实例为大家分享了python实现人机对战井字棋的具体代码,供大家参考,具体内容如下游戏简介:在九宫格内进行,如果一方抢先于另一方向(横、
- 本文实例讲述了JavaScript数据库TaffyDB用法。分享给大家供大家参考。具体如下:TaffyDB 是一个免费开源的 JavaScr
- 八皇后问题描述:在一个8✖️8的棋盘上,任意摆放8个棋子,要求任意两个棋子不能在同一行,同一列,同一斜线上,问有多少种解法。规则分析:任意两
- 1. 笛卡尔乘积表1有m行数据,表2有n行数据,查询结果有m*n行数据。2. 分类(1)按年代分类sql92标准:仅支持内连接sql99标准
- time()在PHP中是得到一个数字,这个数字表示从1970-01-01到现在共走了多少秒,很奇怪吧 不过这样方便计算, 要找出前一天的时间
- 这篇文章主要介绍了python enumerate内置函数用法总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价