0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一文讀懂定時器實現技術

jf_78858299 ? 來源:架構之美 ? 作者: 孫玄 架構之美 ? 2023-04-21 14:36 ? 次閱讀

1. 定時器介紹

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

interval:間隔時間,即定時器需要在interval時間后執(zhí)行

StartTimer:添加一個定時器任務

StopTimer:結束一個定時器任務

PerTickBookkeeping: 檢查定時器系統(tǒng)中,是否有定時器實例已經到期,相當于定義了最小時間粒度。

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

鏈表

排序鏈表

最小堆

時間輪

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

2. 定時器實現方法

2.1 鏈表實現

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

在此方案中,添加定時器就是在鏈表的末尾新增一個節(jié)點,時間復雜度是 O(1)。

如果想要刪除一個定時器的話,我們需要遍歷鏈表找到對應的定時器,時間復雜度是O(n)。

此方案下,每隔elapse時間,系統(tǒng)調用信號進行超時檢查,即PerTickBookkeeping。每次PerTickBookkeeping需要對鏈表所有定時器進行 elapse++,因此可以看出PerTickBookkeeping的時間復雜度是O(N)。

可以看出此方案過于粗暴,所以使用場景極少。

2.2 排序雙向鏈表實現

排序雙向鏈表是在鏈表實現上的優(yōu)化。優(yōu)化思路是降低時間復雜度。

首先,每次PerTickBookkeeping需要自增所有定時器的elapse變量,如果我們將interval變?yōu)榻^對時間,那么我們只需要比較當前時間和interval時間是否相等,減少了對每個定時器的操作。

如果不需要對每個定時器進行操作,我們將定時器進行排序,那么每次PerTickBookkeeping都只需要判斷第一個定時器,時間復雜度為O(1)。

相應的,為了維持鏈表順序,每次新增定時器需要進行鏈表排序時間復雜度為 O(N)。

每次刪除定時器時,由于會持有自己節(jié)點的引用,所以不需要查找其在鏈表中所在的位置,所以時間復雜度為O(1),雙向鏈表的好處。

圖片

圖1 雙向鏈表實現示意圖

2.3 時間輪實現

時間輪的數據結構是數組 + 鏈表。

他的時間輪為數組,新增和刪除一個任務,時間復雜度都是O(1)。

PerTickBookkeeping每次轉動一格,時間復雜度也是O(1)。

2.4 最小堆實現

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

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

圖片

圖3 最小堆

樹的基本操作是插入節(jié)點和刪除節(jié)點。對最小堆而言,為了將一個元素X插入最小堆,我們可以在樹的下一個空閑位置創(chuàng)建一個空穴。如果X可以放在空穴中而不被破壞堆的序,則插入完成。否則就執(zhí)行上濾操作,即交換空穴和它的父節(jié)點上的元素。不斷執(zhí)行上述過程,直到X可以被放入空穴,則插入操作完成。

因此我們可以知道最小堆的插入時間復雜度是O(lgN)。

最小堆的刪除和插入邏輯基本類似,如果不做優(yōu)化,時間復雜度也是O(lgN),但是實際實現方案上,做了延遲刪除操作,時間復雜度為O(1)。

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

可以看到PerTickBookkeeping只處理堆頂定時器,時間復雜度O(1)。

最小堆可以使用數組來進行表示,數組中,當前下標n的左子節(jié)點為2N + 1,當前下標n的右子節(jié)點小標為2N + 2。

圖片

圖4 最小堆的數組表示

3. 定時器不同實現對比

3.1 時間復雜度對比

圖片

圖5 不同實現時間復雜度

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

3.2 使用場景來看

在任務量小的場景下:最小堆實現,可以根據堆頂設置超時時間,數組存儲結構,節(jié)省內存消耗,使用最小堆可以得到比較好的效果。而時間輪定時器,由于需要維護一個線程用來撥動指針,且需要開辟一個bucket數組,消耗內存大,使用時間輪會較為浪費資源。

在任務量大的場景下:最小堆的插入復雜度是O(lgN), 相比時間輪O(1) 會造成性能下降。更適合使用時間輪實現。

在業(yè)界,服務治理的心跳檢測等功能需要維護大量的鏈接心跳,因此時間輪是首選。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • 定時器
    +關注

    關注

    23

    文章

    3248

    瀏覽量

    114816
  • 程序
    +關注

    關注

    117

    文章

    3787

    瀏覽量

    81049
收藏 人收藏

    評論

    相關推薦

    555定時器

    555定時器555定時器555定時器555定時器555定時器555定時器555
    發(fā)表于 11-10 17:25 ?52次下載

    基于STM32定時器實現毫秒延時函數

    STM32定時器包含基本定時器、通用定時器和高級定時器,其中TIM6和TIM7是STM32當中的基本定時器,作為初學者,先從最基本的學起最容
    發(fā)表于 10-12 15:54 ?2.5w次閱讀
    基于STM32<b class='flag-5'>定時器</b><b class='flag-5'>實現</b>毫秒延時函數

    定時器原理以及定時器實現的方式

    定時器原理定時器實現的方式有以下幾種: 基于排序鏈表方式: 通過排序鏈表來保存定時器,由于鏈表是排序好的,所以獲取最?。ㄗ钤绲狡冢┑?/div>
    的頭像 發(fā)表于 08-14 11:15 ?6808次閱讀

    STM32基于cubeMX實現定時器點燈

    概述STM32的常見的定時器資源: 系統(tǒng)嘀嗒定時器SysTick、看門狗定時器WatchDog、實時時鐘RTC、基本定時器、通用定時器、高級
    發(fā)表于 11-23 18:21 ?19次下載
    STM32基于cubeMX<b class='flag-5'>實現</b><b class='flag-5'>定時器</b>點燈

    STM32定時器-基本定時器

    ,分為基本定時器,通用定時器和高級定時器?;?b class='flag-5'>定時器 TIM6 和 TIM7 是個 16 位的只能向上計數的
    發(fā)表于 11-23 18:21 ?31次下載
    STM32<b class='flag-5'>定時器</b>-基本<b class='flag-5'>定時器</b>

    STM32——高級定時器、通用定時器、基本定時器的區(qū)別

    STM32——高級定時器、通用定時器、基本定時器的區(qū)別
    發(fā)表于 11-26 15:21 ?110次下載
    STM32——高級<b class='flag-5'>定時器</b>、通用<b class='flag-5'>定時器</b>、基本<b class='flag-5'>定時器</b>的區(qū)別

    SysTick 定時器

    11.1關于 SysTick 定時器SysTick定時器(又名系統(tǒng)滴答定時器)是存在于Cortex-M3的定時器,只要是ARM Cote
    發(fā)表于 12-05 14:51 ?9次下載
    SysTick <b class='flag-5'>定時器</b>

    labview定時器實現實例分享

    labview定時器實現實例分享
    發(fā)表于 01-11 09:35 ?26次下載

    使用555定時器實現延時關燈

    使用555定時器實現延時關燈
    發(fā)表于 11-21 14:54 ?11次下載

    定時器作用及實現定時器數據結構選取介紹1

    定時器在各種場景都需要用到,比如游戲的Buff實現,Redis中的過期任務,Linux中的定時任務等等。顧名思義,定時器的主要用途是執(zhí)行定時
    的頭像 發(fā)表于 04-21 15:20 ?1204次閱讀
    <b class='flag-5'>定時器</b>作用及<b class='flag-5'>實現</b><b class='flag-5'>定時器</b>數據結構選取介紹1

    定時器作用及實現定時器數據結構選取介紹2

    定時器在各種場景都需要用到,比如游戲的Buff實現,Redis中的過期任務,Linux中的定時任務等等。顧名思義,定時器的主要用途是執(zhí)行定時
    的頭像 發(fā)表于 04-21 15:20 ?1197次閱讀
    <b class='flag-5'>定時器</b>作用及<b class='flag-5'>實現</b><b class='flag-5'>定時器</b>數據結構選取介紹2

    什么是軟件定時器?軟件定時器實現原理

    軟件定時器是用程序模擬出來的定時器,可以由個硬件定時器模擬出成千上萬個軟件定時器,這樣程序在需要使用較多
    的頭像 發(fā)表于 05-23 17:05 ?2793次閱讀

    STM32如何使用定時器實現微秒(us)級延時?

    如何使用定時器實現微秒級延時的步驟: 步驟 1:配置定時器 首先,需要選擇個適合的定時器。大多數STM32微控制
    的頭像 發(fā)表于 11-06 11:05 ?6344次閱讀

    定時器設計實現

    返回ITimer類型的共享指針。其中ITimer類中定義了start和stop方法,用于啟動或停止當前定時器。 TimerManager還有個內部類TimerMessageQueue用于實現
    的頭像 發(fā)表于 11-08 16:50 ?609次閱讀

    如何實現個軟件定時器

    在Linux,uC/OS,FreeRTOS等操作系統(tǒng)中,都帶有軟件定時器,原理大同小異。典型的實現方法是:通過個硬件定時器產生固定的時鐘節(jié)拍,每次硬件
    的頭像 發(fā)表于 04-29 11:00 ?657次閱讀