這裏的Timer,是指定時器,現代操做系統,定時器無處不在,以致於有些將linux kernel的書,都須要單獨列出一章,來將linux是如何管理這些定時器的。管理定時器其實主要的步驟有如下3步:
1.生成定時器(這裏面最終要的是給予定時器其到期時間以及到期後要產生的動做)
2.將定時器放入一個數據結構中,以便系統可以定時的掃描檢查這些定時器是否到期,是否須要觸發
3.按期檢查定時器是否到期 linux
通常可以想到的最直觀的實現定時器的辦法,就是在定時器裏插入一個絕對時間,而後將定時器放入一個鏈表,每次輪詢時,將該鏈表總體輪詢一遍,從而檢查有哪些定時器到期了。那麼這樣的時間複雜度爲:插入定時器 o(1); 每次輪詢o(n). 算法
如今的linux內核中,對timer的管理實際上是根據timer離當前時間的遠近,將其存放到不一樣的雙向隊列數組中,每一個隊列數組長度同樣,好比都是2的8次方;(具體是2的幾回方,這個還要依賴其餘條件,這裏只是舉個例子)間隔時間小於2的8次方的,存放在第一個雙向隊列數組裏;間隔時間大於等於2的8次方但小於2的16次方的,則存放在第二個雙向隊列數組裏,以此類推;
而後每一個2的8次方個週期,對上面的雙向隊列數組進行從新安排,好比這個時候,須要將第二個數組裏的有些隊列移動到地一個數組裏。這樣在實現時,插入定時器o(1),其只須要計算該timer的時間和當前時間的關係,從而計算出應該將其放置第幾個數組的第幾個雙向隊列上(同一個數組的某個雙向對列上,存放的都是時間同樣的timer)便可(基本上是最簡單而直接的hash算法);插入定時器o(1),平時輪詢時,只要取最近的那個數組裏的對應timer便可,時間複雜度爲o(1),每隔指定的週期後(好比2的8次方個週期後)論詢一次,這個時候由於要對全部的現存的timer進行調整,最壞時間複雜度是o(n). 數組
而Netty中的Timer管理,則是使用了所謂的Hashed Wheel模式,在數據結構上,其有一個循環數組,這個循環數組有n個bucket(假設爲8),能夠用來存放Timer鏈表;Hash Wheel裏有2個週期,一個週期是單次輪詢的週期,假設爲100個Tick;第二個週期是輪詢完數組的週期,那麼其大小爲n*Tick(8*100就爲800),假設叫round 週期;那麼在每次插入一個timer時,會根據timer的觸發時間,計算出其應該存放在哪一個bucket的鏈表中(好比timer距離當前週期爲2550tick,那麼該Timer就會放在(2550%(n*100Tick))/100Tick=2,這裏取celling),在timer插入到bucket中的同時,按照這種算法,相隔round週期整數倍的Timer會存放在相同的bucket的鏈表中,爲了區分round週期,因此每一個timer在存放時,還會有一個數值用來村放其距離當前時間還剩多少個round週期(剛纔的例子round爲3)。當timer插入後,這樣輪詢的時候就比較方便,輪詢時,會有一個cursor,每隔一個週期就加一,論詢時該cursor指向數組的哪一個bucket,就檢查該bucket中的全部timer,主要是檢查該timer的round週期是否爲0,若是不是0,則將其值減1,而後將其歸還(cursor不斷增長,當cursor下次指向該bucket時,通過的時間爲一個round週期)。而若是round週期已經爲0了,則說明該timer須要被觸發了,從而觸發該timer。這樣計算時間複雜度的話,插入的時候,其時間複雜度爲o(1),而在輪詢的時候,其時間複雜度也可理解爲o(1). 數據結構
Hashed Wheel Timing原理圖 操作系統
比較一下linux內核裏的timer管理和netty的timer管理,會發現,若是管理的timer的觸發時間都距離當前時間比較近,那麼linux和netty的效率應該都差很少(linux這個時候,當間隔的大週期發生的時候,也基本不用調整數組,從而不會發生時間複雜度爲o(n)的操做)。而若是管理了較多的距離當前時間很長的timer(此時的linux,會在除了第一個數組外的其餘數組裏也要存放timer;而netty中,則會在每一個bucket的鏈表中,存放較多的round週期大於0的timer),那麼這個時候,linux平時輪詢時,;處理的都是確實須要被觸發的timer,而netty,極可能會碰到不少不要觸發的timer,而後把這些timer的round週期減一,這種狀況下,對於平時的輪詢,linux是要優於netty;而當碰到大週期時,linux的耗時會超過netty。至關與在這種情形下,netty是把對長時間timer的處理分散在每次輪詢中,而linux則是把它集中在一個週期裏來作。linux的這種作法,在通常的情景下應該是ok的,可是在realtime os的狀況下,應該是有問題的。 netty
相比較與公司本身實現的一個二方庫,裏面其實也須要用到超時機制,可是實現起來就是很直觀,這也沒有辦法,畢竟你們都時間有限,有的時候仍是以快速實現業務爲主,沒有太多時間把一些技術點考慮的很深遠,可是這個時候咱們仍是能夠借鑑一下開源軟件中的相似解決方案,拿來爲己所用。開源軟件可以聚集互聯網上不少人的智慧,這多是不少公司的技術力量都不可以比擬的,這可能也就是開源的魅力所在。 隊列