golang?墻上時(shí)鐘與單調(diào)時(shí)鐘的實(shí)現(xiàn)
墻上時(shí)鐘與單調(diào)時(shí)鐘
墻上時(shí)鐘
墻上時(shí)鐘也稱為墻上時(shí)間。大多是1970年1月1日(UTC)以來(lái)的秒數(shù)和毫秒數(shù)。
墻上時(shí)間可以和NTP(Network Time Protocal,網(wǎng)絡(luò)時(shí)間協(xié)議)同步,但是如果本地時(shí)鐘遠(yuǎn)遠(yuǎn)快于NTP服務(wù)器,則強(qiáng)制重置之后會(huì)跳到先前某個(gè)時(shí)間點(diǎn)。(這里不是很確定,猜測(cè)是如果時(shí)間差的不多,則調(diào)整石英晶體振蕩器的頻率,慢慢一致。如果差很多,則強(qiáng)行一致)
單調(diào)時(shí)鐘
機(jī)器大多有自己的石英晶體振蕩器,并將其作為計(jì)時(shí)器。單調(diào)時(shí)鐘的絕對(duì)值沒(méi)有任何意義,根據(jù)操作系統(tǒng)和語(yǔ)言的不同,單調(diào)時(shí)鐘可能在程序開(kāi)始時(shí)設(shè)為0、或在計(jì)算機(jī)啟動(dòng)后設(shè)為0等等。但是通過(guò)比較同一臺(tái)計(jì)算機(jī)上兩次單調(diào)時(shí)鐘的差,可以獲得相對(duì)準(zhǔn)確的時(shí)間間隔。
Time的結(jié)構(gòu)
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 ... } 復(fù)制代碼
wall和ext共同記錄了時(shí)間,但是分為兩種情況,一種是沒(méi)有記錄單調(diào)時(shí)鐘(比如是通過(guò)字符串解析得到的時(shí)間),另一種是記錄了單調(diào)時(shí)鐘(比如通過(guò)Now)。
wall的第一位是一個(gè)標(biāo)記位
如果為1,則表示記錄了單調(diào)時(shí)鐘。則wall的2-34(閉區(qū)間)位記錄了從1885-1-1到現(xiàn)在的秒數(shù),最后30位記錄了納秒數(shù)。而ext記錄了從程序開(kāi)始運(yùn)行到現(xiàn)在經(jīng)過(guò)的單調(diào)時(shí)鐘數(shù)。
如果為0,則表示沒(méi)有記錄單調(diào)時(shí)鐘。則wall的2-34(閉區(qū)間)位全部為0(那最后30位是啥?)。而ext記錄了從1-1-1到現(xiàn)在經(jīng)過(guò)的秒數(shù)。
Since的實(shí)現(xiàn)
這里比較關(guān)鍵的代碼是第914行的runtimeNano() - startNano
。startNano
的含義還是直接上代碼比較明了。
var startNano = 0 ? func init(){ startNano = runtimeNano() }
runtimeNano()
是調(diào)用了匯編,獲取了操作系統(tǒng)當(dāng)前的單調(diào)時(shí)鐘。前面說(shuō)過(guò),單調(diào)時(shí)鐘的絕對(duì)值沒(méi)有什么意義。因此這里將兩個(gè)時(shí)間相減,得到了從程序開(kāi)始到現(xiàn)在的單調(diào)時(shí)鐘。
然后看一下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 } }
這里我們只需要關(guān)注2-13行即可。除去了范圍檢查,這里的主要邏輯就是兩個(gè)Time的ext相減。而ext又都代表了單調(diào)時(shí)鐘,所以最后返回的是單調(diào)時(shí)鐘的差值。
小結(jié)
在分布式系統(tǒng)中,我們經(jīng)常需要判斷時(shí)間間隔來(lái)檢測(cè)心跳。而墻上時(shí)鐘與NTP的組合可能會(huì)帶來(lái)時(shí)間的前后跳躍與閃爍,所以使用單調(diào)時(shí)鐘更加安全和保險(xiǎn)。
在go語(yǔ)言中,沒(méi)有直接調(diào)用調(diào)用時(shí)鐘的函數(shù)??梢酝ㄟ^(guò)time.Now()
獲得帶單調(diào)時(shí)鐘的Time
結(jié)構(gòu)體,并通過(guò)Since和Until獲得相對(duì)準(zhǔn)確的時(shí)間間隔。
參考資料
go1.14.2 源碼
數(shù)據(jù)密集型應(yīng)用系統(tǒng)設(shè)計(jì)(書(shū))
到此這篇關(guān)于golang 墻上時(shí)鐘與單調(diào)時(shí)鐘的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)golang 墻上時(shí)鐘與單調(diào)時(shí)鐘內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GoFrame框架數(shù)據(jù)校驗(yàn)之校驗(yàn)對(duì)象校驗(yàn)結(jié)構(gòu)體
這篇文章主要為大家介紹了GoFrame框架數(shù)據(jù)校驗(yàn)之校驗(yàn)對(duì)象校驗(yàn)結(jié)構(gòu)體示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06使用go net實(shí)現(xiàn)簡(jiǎn)單的redis通信協(xié)議
本文主要介紹了go net實(shí)現(xiàn)簡(jiǎn)單的redis通信協(xié)議,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12Golang利用casbin實(shí)現(xiàn)權(quán)限驗(yàn)證詳解
Casbin是一個(gè)強(qiáng)大的、高效的開(kāi)源訪問(wèn)控制框架,其權(quán)限管理機(jī)制支持多種訪問(wèn)控制模型,Casbin只負(fù)責(zé)訪問(wèn)控制。本文將利用casbin實(shí)現(xiàn)權(quán)限驗(yàn)證功能,需要的可以參考一下2023-02-02解決Go?Json?Unmarshal反序列化丟失數(shù)字精度問(wèn)題
業(yè)務(wù)會(huì)使用?id生成器?產(chǎn)生的?分布式唯一ID,長(zhǎng)度比較長(zhǎng),所以代碼反序列化時(shí),會(huì)出現(xiàn)精度丟失問(wèn)題,那如何解決呢,下面小編就來(lái)和大家詳細(xì)講講2023-08-08詳解golang開(kāi)發(fā)中http請(qǐng)求redirect的問(wèn)題
這篇文章主要介紹了詳解golang開(kāi)發(fā)中http請(qǐng)求redirect的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Golang Mutex實(shí)現(xiàn)互斥的具體方法
Mutex是Golang常見(jiàn)的并發(fā)原語(yǔ),在開(kāi)發(fā)過(guò)程中經(jīng)常使用到,本文主要介紹了Golang Mutex實(shí)現(xiàn)互斥的具體方法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-04-04