網站首頁 編程語言 正文
墻上時鐘與單調時鐘
墻上時鐘
墻上時鐘也稱為墻上時間。大多是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分析
一個commit
go1.14.2 源碼
數據密集型應用系統設計(書)
原文鏈接:https://juejin.cn/post/7122472804129341476
相關推薦
- 2022-06-25 Python制作簡易計算器功能_python
- 2022-03-08 C語言設計前中后隊列實例代碼_C 語言
- 2022-07-06 安裝pytorch報錯torch.cuda.is_available()=false問題的解決過程_
- 2022-09-30 Pygame游戲開發之太空射擊實戰子彈與碰撞處理篇_python
- 2023-03-25 Redis實現UV統計的示例代碼_Redis
- 2023-04-07 C++11學習之多線程的支持詳解_C 語言
- 2022-11-09 React的特征單向數據流學習_React
- 2022-07-11 Android?studio實現左右滑動切換圖片_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支