系統梳理主流定時器演算法實現的差異以及應用

奈學教育發表於2020-06-08

這一篇文章系統的梳理主流定時器演算法實現的差異以及應用地方。

1. 定時器介紹

程式裡的定時器主要實現的功能是在未來的某個時間點執行相應的邏輯。在定時器模型中,一般有如下幾個定義。 

interval:間隔時間,即定時器需要在interval時間後執行

StartTimer:新增一個定時器任務

StopTimer:結束一個定時器任務

PerTickBookkeeping: 檢查定時器系統中,是否有定時器例項已經到期,相當於定義了最小時間粒度。

常見的實現方法有如下幾種:

連結串列

排序連結串列

最小堆

時間輪 

接下來我們一起看下這些方法的具體實現原理。

2. 定時器實現方法

2.1 連結串列實現

連結串列的實現方法比較粗糙。連結串列用於儲存所有的定時器,每個定時器都含有interval 和 elapse 兩個時間引數,elapse表示當前被tickTimer了多少次。當elapse 和interval相等時,表示定時器到期。

在此方案中,新增定時器就是在連結串列的末尾新增一個節點,時間複雜度是 O(1)。如果想要刪除一個定時器的話,我們需要遍歷連結串列找到對應的定時器,時間複雜度是O(n)。此方案下,每隔elapse時間,系統呼叫訊號進行超時檢查,即PerTickBookkeeping。每次PerTickBookkeeping需要對連結串列所有定時器進行 elapse++,因此可以看出PerTickBookkeeping的時間複雜度是O(N)。可以看出此方案過於粗暴,所以使用場景極少

2.2 排序雙向連結串列實現

排序雙向連結串列是在連結串列實現上的最佳化。最佳化思路是降低時間複雜度。

首先,每次PerTickBookkeeping需要自增所有定時器的elapse變數,如果我們將interval變為絕對時間,那麼我們只需要比較當前時間和interval時間是否相等,減少了對每個定時器的操作。如果不需要對每個定時器進行操作,我們將定時器進行排序,那麼每次PerTickBookkeeping都只需要判斷第一個定時器,時間複雜度為O(1)。相應的,為了維持連結串列順序,每次新增定時器需要進行連結串列排序時間複雜度為 O(N)。每次刪除定時器時,由於會持有自己節點的引用,所以不需要查詢其在連結串列中所在的位置,所以時間複雜度為O(1),雙向連結串列的好處。

圖1 雙向連結串列實現示意圖

2.3 時間輪實現

時間輪示意圖如下:

圖2 時間輪

時間輪的資料結構是陣列 + 連結串列。 他的時間輪為陣列,新增和刪除一個任務,時間複雜度都是O(1)。PerTickBookkeeping每次轉動一格,時間複雜度也是O(1)。

2.4 最小堆實現

最小堆是堆的一種, (堆是一種二叉樹), 指的是堆中任何一個父節點都小於子節點, 子節點順序不作要求。

二叉排序樹(BST)指的是: 左子樹節點小於父節點, 右子樹節點大於父節點, 對所有節點適用

圖3 最小堆

樹的基本操作是插入節點和刪除節點。對最小堆而言,為了將一個元素X插入最小堆,我們可以在樹的下一個空閒位置建立一個空穴。如果X可以放在空穴中而不被破壞堆的序,則插入完成。否則就執行上濾操作,即交換空穴和它的父節點上的元素。不斷執行上述過程,直到X可以被放入空穴,則插入操作完成。因此我們可以知道最小堆的插入時間複雜度是O(lgN)。最小堆的刪除和插入邏輯基本類似,如果不做最佳化,時間複雜度也是O(lgN),但是實際實現方案上,做了延遲刪除操作,時間複雜度為O(1)。

延遲刪除即設定定時器的執行回撥函式為空,每次最小堆超時,將觸發pop_heap,pop會重新調整最小堆,最終刪除的定時器將調整到堆頂,但是回撥函式不處理。

可以看到PerTickBookkeeping只處理堆頂定時器,時間複雜度O(1)。最小堆可以使用陣列來進行表示,陣列中,當前下標n的左子節點為2N + 1,當前下標n的右子節點小標為2N + 2。

圖4 最小堆的陣列表示

3. 定時器不同實現對比

3.1 時間複雜度對比

圖5 不同實現時間複雜度

從上面的介紹來看,時間輪的時間複雜度最小、效能最好。

3.2 使用場景來看

在任務量小的場景下:最小堆實現,可以根據堆頂設定超時時間,陣列儲存結構,節省記憶體消耗,使用最小堆可以得到比較好的效果。而時間輪定時器,由於需要維護一個執行緒用來撥動指標,且需要開闢一個bucket陣列,消耗記憶體大,使用時間輪會較為浪費資源。在任務量大的場景下:最小堆的插入複雜度是O(lgN), 相比時間輪O(1) 會造成效能下降。更適合使用時間輪實現。在業界,服務治理的心跳檢測等功能需要維護大量的連結心跳,因此時間輪是首選。

更多免費技術資料及影片


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69976011/viewspace-2696994/,如需轉載,請註明出處,否則將追究法律責任。

相關文章