golang 墙上时钟与单调时钟的实现

 更新时间:2022年07月21日 16:08:59   作者:浪狼郎  
本文主要介绍了golang 墙上时钟与单调时钟的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

墙上时钟与单调时钟

墙上时钟

墙上时钟也称为墙上时间。大多是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() - startNanostartNano的含义还是直接上代码比较明了。

 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分析

一个commit

go1.14.2 源码

数据密集型应用系统设计(书)

到此这篇关于golang 墙上时钟与单调时钟的实现的文章就介绍到这了,更多相关golang 墙上时钟与单调时钟内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang中可比较的数据类型详解

    Golang中可比较的数据类型详解

    在日常开发中,比较操作是最常用的基本操作之一,可以用来判断变量之间是否相等或者对应的大小关系,本文将深入解析 Golang 中可比较的数据类型,并结合代码示例来说明如何在不同情况下进行比较,需要的朋友可以参考下
    2024-01-01
  • Go语言的反射机制详解

    Go语言的反射机制详解

    本文详细讲解了Go语言的反射机制,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • golang内置函数len的小技巧

    golang内置函数len的小技巧

    len是很常用的内置函数,可以测量字符串、slice、array、channel以及map的长度/元素个数。本文就来介绍一下其他小技巧,感兴趣的可以了解一下
    2021-07-07
  • Golang pprof监控之cpu占用率统计原理详解

    Golang pprof监控之cpu占用率统计原理详解

    经过前面的几节对pprof的介绍,对pprof统计的原理算是掌握了七八十了,但唯独还没有分析pprof 工具是如何统计cpu使用情况的,今天我们来分析下这部分
    2023-04-04
  • gin项目部署到服务器并后台启动的步骤

    gin项目部署到服务器并后台启动的步骤

    本文主要介绍了gin项目部署到服务器并后台启动的步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • 在Go中格式化字符串的几种常用方法

    在Go中格式化字符串的几种常用方法

    Go对字符串格式化提供了良好的支持,这篇文章主要给大家介绍了关于在Go中格式化字符串的几种常用方法,文中通过代码介绍的非常详细,对大家学习或者使用Go具有一定的参考价值,需要的朋友可以参考下
    2023-10-10
  • Go语言bufio库的全面指南与实战技巧详解

    Go语言bufio库的全面指南与实战技巧详解

    这篇文章主要为大家全面介绍一下 bufio 库的核心组件与功能,包括 Reader、Writer 和 Scanner 等并深入探讨它们在实际编程中的运用场景和技巧,感兴趣的可以了解下
    2024-01-01
  • Golang测试func TestXX(t *testing.T)的使用详解

    Golang测试func TestXX(t *testing.T)的使用详解

    一般Golang中的测试代码都以xxx_test.go的样式,在命名测试函数的时候以Testxx开头,下面给大家介绍Golang测试func TestXX(t *testing.T)的使用,感兴趣的朋友跟随小编一起看看吧
    2024-08-08
  • Go语言面向对象中的多态你学会了吗

    Go语言面向对象中的多态你学会了吗

    面向对象中的多态(Polymorphism)是指一个对象可以具有多种不同的形态或表现方式,本文将通过一些简单的示例为大家讲解一下多态的实现,需要的可以参考下
    2023-07-07
  • 浅谈Go1.18中的泛型编程

    浅谈Go1.18中的泛型编程

    本文主要介绍了Go1.18中的泛型编程,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12

最新评论