Go 标准库 time 包之 monotonic clocks

继续上一章节未完成的介绍,本章节我们主要讲解下 monotonic clock ( 单调时钟 ) 在 time 的运用,包括但不限于如何使用 单调时间 来测量两个时间的间隔

事先声明下,本章节的内容是关于 time 包中的方法如何使用 monotonic clock 的细节,但这些细节并不是使用 time 包所必须的。

Time 结构包含了 monotonic clocks

这是第一个认知,也是最重要的认知。Time 对象不仅包含了 1970 年 1 月 1 日 0 时 0 分 0 秒以来的时间戳,还包括了系统启动以来的 monotonic clock。

time.Now 这个方法返回的 Time 结构对象就包含了 monotonic clock 。( 关于 Time 结构的更多知识,可以访问我们的 Go 标准库 time 包之 Time 结构 )

如果一个 Time 结构对象 t 包含了 monotonic clock 读数 ( reading ) ,那么 t.Add() 方法会将相同的持续时间间隔 ( during time ) 同时添加到 wall time 和 monotonic clock 的读数上以计算结果。

你可能会问,t.AddDate(y, m, d)t.Round(d)t.Truncate(d) 方法不是根据 wall clock 来计算的吗 ?

是的,它们的确是根据 wall clock 来计算的,只不过它们在进行计算的时候会把 monotonic clock 读数给去除掉,只计算 wall clock

另一方面,你可能也直到,t.Int.Localt.UTC 只是用于解释 wall clock 时间,因此呢,它们也会从结果中去除任何 monotonic clock 读数

上面这些方法,去除 monotonic clock 的标准方式就是运行 t = t.Round(0) ,也就是四舍五入取整。

如果 Time 结构的对象 tu 同时都包含了 monotonic clock 读数,那么 t.After(u)t.Before(u)t.Equal(u)t.Sub(u) 仅仅只会使用 monotonic clock 读数进行计算,而忽略 wall time 读数

但,只要 tu 中的任何一个对象实例不包含 monotonic clock,那么这些上面这些方法就会回退到使用 wall clock 而忽略另一个实例的 monotonic clock

解释器来有点费劲,我们直接看源码

func (t Time) Before(u Time) bool {
    if t.wall&u.wall&hasMonotonic != 0 {
        return t.ext < u.ext
    }
    return t.sec() < u.sec() || t.sec() == u.sec() && t.nsec() < u.nsec()
}

上面这些方法,无不例外,都有下面这段语句

if t.wall&u.wall&hasMonotonic != 0 {
    return t.ext < u.ext
}

hasMonotonic !=0 ,也就是存在 monotonic clock,就会直接比较 ext 这个属性,也就是 monotonic clock 读数

因为 monotonic clock 的特性,在某些系统上,如果计算机进入了睡眠状态,那么 monotonic clock 就会暂停 ( 不是停止 ),直到下一次计算机唤醒才会继续增加。在这样的系统上,因为 monotonic clock 的读数是不准确的,所以可能导致像 t.Sub(u) 无法准确反映 tu 之间经过的实际时间

因为这种特性,所以 monotonic clock 读数在当前进程之外没有任何意义,直接导致了 t.GobEncodet.MarshalBinaryt.MarshalJSONt.MarshalText 生成的序列化结果省略了 monotonic clock 读数

更重要的是,t.Format 也忽略了 monotonic clock 读数,没有任何格式化字符来使用它

比上面更惨的是 ( 对 monotonic clock 而言 ),构造函数有 time.Datetime.Parsetime.ParseInLocationtime.Unix,以及一些反序列化方法,比如 t.GobDecodet.UnmarshalBinaryt.UnmarshalJSONt.UnmarshalText 总是创建没有 monotonic clock 读数的时间

当然了,对 monotonic clock 而言,还是有好消息的,那就是 Go 语言中的 == 运算符不仅比较 wall time ,还比较 Location 和 monotonic clock 读数

对于调试,利好消息就是,t.String 的结果会包括 monotonic clock 读数 ( 如果存在 ) 。针对 monotonic clock 读数的不同导致的 t != u ,可以使用打印 t.String()u.String() 来看看到这种不同之处。

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.