1. 程式人生 > >時間輪演算法

時間輪演算法

前言

現實開發中有許多的延遲操作,比如定時清理過期資料等,在JDK中自帶的Timer或者DelayQueue來實現延遲的功能,但很多開源的中介軟體中並沒有使用Timer或者DelayQueue來實現而是使用基於時間輪演算法來實現執行延遲任務功能,例如2.7.0以上的Dubbo基於時間輪實現了,失敗定時重發,心跳檢測等延遲操作。JDK的Timer和DelayQueue插入和刪除操作的平均時間複雜度為O(nlog(n))並不能滿足的高效能插入刪除的要求,而而基於時間輪可以將插入和刪除操作的時間複雜度都降為O(1) 。

實現

時間輪是參考鐘表盤來實現,鐘表盤上的錶針會在固定時間後向前走一格,走完12格後又回到原來位置重複上面流程,時間輪也類似定義了幾個格,在固定時間在這幾個格上走動。盜圖看下結構

如上圖,時間輪有多個時間格組成,每個時間格里放置了任務佇列,當走到某個時間格時會執行當前時間格里的任務。時間輪的每個時間格用slot表示,時間輪的時間格長度是固定的用wheelLength表示,每個時間格走動的間隔時間也是固定的用tickDuration表示,假設當前指向時間格的第一個位置,要執行一個延遲時間為deadline的任務,那麼需要先找到對應的slot將任務加入才能順利執行,其對應的計算公式:slot = (deadline / tickDuration)%wheelLength;走完一圈時間輪所需的時間為:loopDuration = tickDuration*wheelLength,如果任務的deadline > loopDuration,那麼第一輪走到對應的slot是不能執行此任務,需要計算執行此任務需要經過輪數,計算格式為:remainingRounds = deadline / tickDuration / wheelLength;也就是說次任務需要再經過remainingRounds+1輪並走到對應的slot才能執行。

舉個例子:

定義時間格長度wheelLength=12,每個時間格間隔時間tickDuration=1s,假設當前指向時間格的第一個位置,如果執行一個需要20s後執行的延遲任務,根據公式slot=8,remainingRound=1,也就是說時間輪走2圈,並且走到時間格位置為8的地方