亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Redis定時(shí)任務(wù)原理的實(shí)現(xiàn)

 更新時(shí)間:2022年03月07日 09:37:04   作者:心城以北  
本文主要是基于?redis?6.2?源碼進(jìn)行分析定時(shí)事件的數(shù)據(jù)結(jié)構(gòu)和常見操作,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文主要是基于 redis 6.2 源碼進(jìn)行分析定時(shí)事件的數(shù)據(jù)結(jié)構(gòu)和常見操作。

數(shù)據(jù)結(jié)構(gòu)

在 redis 中通過 aeTimeEvent 結(jié)構(gòu)來創(chuàng)建定時(shí)任務(wù)事件,代碼如下:

/* Time event structure */
typedef struct aeTimeEvent {
? ? // 標(biāo)識(shí)符
? ? long long id; /* time event identifier. */
? ? // 定時(shí)納秒數(shù)
? ? monotime when;
? ? // 定時(shí)回調(diào)函數(shù)
? ? aeTimeProc *timeProc;
? ? // 注銷定時(shí)器時(shí)候的回調(diào)函數(shù)
? ? aeEventFinalizerProc *finalizerProc;
? ? void *clientData;
? ? struct aeTimeEvent *prev;
? ? struct aeTimeEvent *next;
? ? int refcount; /* refcount to prevent timer events from being
? ?? ??? ? ? * freed in recursive time event calls. */
} aeTimeEvent;

常見操作

1. 創(chuàng)建定時(shí)事件

redis 中最重要的定時(shí)函數(shù)且是周期執(zhí)行的函數(shù),使用的是 serverCron 函數(shù)。在 redis 中由于定時(shí)任務(wù)比較少,因此并沒有嚴(yán)格的按照過期時(shí)間來排序的,而是按照 id自增 + 頭插法 來保證基本有序。

if (aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
? serverPanic("Can't create event loop timers.");
? exit(1);
}

//創(chuàng)建定時(shí)器對(duì)象
long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
? ? ? ? aeTimeProc *proc, void *clientData,
? ? ? ? aeEventFinalizerProc *finalizerProc)
{
? ? long long id = eventLoop->timeEventNextId++;
? ? aeTimeEvent *te;

? ? te = zmalloc(sizeof(*te));
? ? if (te == NULL) return AE_ERR;
? ? te->id = id;
? ? te->when = getMonotonicUs() + milliseconds * 1000;
? ? te->timeProc = proc;
? ? te->finalizerProc = finalizerProc;
? ? te->clientData = clientData;
? ? te->prev = NULL;
? ? // 頭插法?
? ? te->next = eventLoop->timeEventHead;
? ? te->refcount = 0;
? ? if (te->next)
? ? ? ? te->next->prev = te;
? ? eventLoop->timeEventHead = te;
? ? return id;
}

2. 觸發(fā)定時(shí)事件

redis 中是采用 IO 復(fù)用來進(jìn)行定時(shí)任務(wù)的。

查找距離現(xiàn)在最近的定時(shí)事件,見 usUntilEarliestTimer

?
/* How many microseconds until the first timer should fire.
?* If there are no timers, -1 is returned.
?*
?* Note that's O(N) since time events are unsorted.
?* Possible optimizations (not needed by Redis so far, but...):
?* 1) Insert the event in order, so that the nearest is just the head.
?* ? ?Much better but still insertion or deletion of timers is O(N).
?* 2) Use a skiplist to have this operation as O(1) and insertion as O(log(N)).
?*/
static int64_t usUntilEarliestTimer(aeEventLoop *eventLoop) {
? ? aeTimeEvent *te = eventLoop->timeEventHead;
? ? if (te == NULL) return -1;

? ? aeTimeEvent *earliest = NULL;
? ? while (te) {
? ? ? ? if (!earliest || te->when < earliest->when)
? ? ? ? ? ? earliest = te;
? ? ? ? te = te->next;
? ? }

? ? monotime now = getMonotonicUs();
? ? return (now >= earliest->when) ? 0 : earliest->when - now;
}

?

這里時(shí)間復(fù)雜度可能比較高,實(shí)際中需要結(jié)合具體場(chǎng)景使用。

更新剩余過期時(shí)間,想想為啥呢?因?yàn)槲覀兦懊嫣岬竭^,IO 復(fù)用有可能因?yàn)?IO 事件返回,所以需要更新。

if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
? usUntilTimer = usUntilEarliestTimer(eventLoop);

if (usUntilTimer >= 0) {
? tv.tv_sec = usUntilTimer / 1000000;
? tv.tv_usec = usUntilTimer % 1000000;
? tvp = &tv;
} else {
? if (flags & AE_DONT_WAIT) {
? ? // 不等待
? ? tv.tv_sec = tv.tv_usec = 0;
? ? tvp = &tv;
? } else {
? ? /* Otherwise we can block */
? ? tvp = NULL; /* wait forever */
? }
}

3. 執(zhí)行定時(shí)事件

一次性的執(zhí)行完直接刪除,周期性的執(zhí)行完在重新添加到鏈表。

/* Process time events */
static int processTimeEvents(aeEventLoop *eventLoop) {
? int processed = 0;
? aeTimeEvent *te;
? long long maxId;

? te = eventLoop->timeEventHead;
? maxId = eventLoop->timeEventNextId-1;
? monotime now = getMonotonicUs();
??
? // 刪除定時(shí)器
? while(te) {
? ? long long id;
?? ??? ?
? ? // 下一輪中對(duì)事件進(jìn)行刪除
? ? /* Remove events scheduled for deletion. */
? ? if (te->id == AE_DELETED_EVENT_ID) {
? ? ? aeTimeEvent *next = te->next;
? ? ? /* If a reference exists for this timer event,
? ? ? ? ? ? ?* don't free it. This is currently incremented
? ? ? ? ? ? ?* for recursive timerProc calls */
? ? ? if (te->refcount) {
? ? ? ? te = next;
? ? ? ? continue;
? ? ? }
? ? ? if (te->prev)
? ? ? ? te->prev->next = te->next;
? ? ? else
? ? ? ? eventLoop->timeEventHead = te->next;
? ? ? if (te->next)
? ? ? ? te->next->prev = te->prev;
? ? ? if (te->finalizerProc) {
? ? ? ? te->finalizerProc(eventLoop, te->clientData);
? ? ? ? now = getMonotonicUs();
? ? ? }
? ? ? zfree(te);
? ? ? te = next;
? ? ? continue;
? ? }
? ??
? ? if (te->id > maxId) {
? ? ? te = te->next;
? ? ? continue;
? ? }

? ? if (te->when <= now) {
? ? ? int retval;

? ? ? id = te->id;
? ? ? te->refcount++;
? ? ? // timeProc 函數(shù)返回值 retVal 為時(shí)間事件執(zhí)行的間隔
? ? ? retval = te->timeProc(eventLoop, id, te->clientData);
? ? ? te->refcount--;
? ? ? processed++;
? ? ? now = getMonotonicUs();
? ? ? if (retval != AE_NOMORE) {
? ? ? ? te->when = now + retval * 1000;
? ? ? } else {
? ? ? ? // 如果超時(shí)了,那么標(biāo)記為刪除
? ? ? ? te->id = AE_DELETED_EVENT_ID;
? ? ? }
? ? }
? ? // 執(zhí)行下一個(gè)
? ? te = te->next;
? }
? return processed;
}

總結(jié)

優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單
缺點(diǎn):如果定時(shí)任務(wù)很多,效率比較低。

到此這篇關(guān)于Redis定時(shí)任務(wù)原理的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Redis定時(shí)任務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • windows上修改redis端口號(hào)的操作步驟

    windows上修改redis端口號(hào)的操作步驟

    redis是一個(gè)開源的內(nèi)存數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng),常用做數(shù)據(jù)庫、緩存和消息代理,默認(rèn)的端口號(hào)為6379,那么如何在windows上修改redis端口號(hào),接下來本文給大家詳細(xì)介紹了windows上修改redis端口號(hào)的操作方法,需要的朋友可以參考下
    2024-02-02
  • 解析Redis Cluster原理

    解析Redis Cluster原理

    redis最開始使用主從模式做集群,若master宕機(jī)需要手動(dòng)配置slave轉(zhuǎn)為master;后來為了高可用提出來哨兵模式,該模式下有一個(gè)哨兵監(jiān)視master和slave,若master宕機(jī)可自動(dòng)將slave轉(zhuǎn)為master,但它也有一個(gè)問題,就是不能動(dòng)態(tài)擴(kuò)充;所以在3.x提出cluster集群模式
    2021-06-06
  • redis底層數(shù)據(jù)結(jié)構(gòu)之skiplist實(shí)現(xiàn)示例

    redis底層數(shù)據(jù)結(jié)構(gòu)之skiplist實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了redis底層數(shù)據(jù)結(jié)構(gòu)之skiplist實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Centos7 Redis主從搭建配置的實(shí)現(xiàn)

    Centos7 Redis主從搭建配置的實(shí)現(xiàn)

    這篇文章主要介紹了Centos7 Redis主從搭建配置的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-06-06
  • 詳細(xì)聊聊Redis的過期策略

    詳細(xì)聊聊Redis的過期策略

    redis 過期策略是定期刪除+惰性刪除,下面這篇文章主要給大家介紹了關(guān)于Redis過期策略的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-01-01
  • Redis過期鍵的刪除策略分享

    Redis過期鍵的刪除策略分享

    redis是內(nèi)存型數(shù)據(jù)庫,可對(duì)鍵設(shè)置過期時(shí)間,當(dāng)鍵過期時(shí)時(shí)怎么淘汰這些鍵的呢?我們先來想一想,如果讓我們?cè)O(shè)計(jì),我們會(huì)想到哪些過期刪除策略呢?本文給大家詳細(xì)介紹了Redis過期鍵的刪除策略,需要的朋友可以參考下
    2024-11-11
  • 一文詳解Redis在Ubuntu系統(tǒng)上的安裝步驟

    一文詳解Redis在Ubuntu系統(tǒng)上的安裝步驟

    安裝redis在Ubuntu上有多種方法,下面這篇文章主要給大家介紹了關(guān)于Redis在Ubuntu系統(tǒng)上安裝的相關(guān)資料,文中通過圖文以及代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-07-07
  • Redis未授權(quán)訪問配合SSH key文件利用詳解

    Redis未授權(quán)訪問配合SSH key文件利用詳解

    這篇文章主要給大家介紹了關(guān)于Redis未授權(quán)訪問配合SSH key文件利用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • MyBatis緩存和二級(jí)緩存整合Redis的解決方案

    MyBatis緩存和二級(jí)緩存整合Redis的解決方案

    這篇文章主要介紹了MyBatis緩存和二級(jí)緩存整合Redis,將MyBatis緩存和二級(jí)緩存整合Redis,可以提高查詢效率,同時(shí)也能保證數(shù)據(jù)的可靠性和一致性,需要的朋友可以參考下
    2023-07-07
  • 詳解redis分布式鎖的這些坑

    詳解redis分布式鎖的這些坑

    在很多互聯(lián)網(wǎng)產(chǎn)品應(yīng)用中,有些場(chǎng)景需要加鎖處理,比如:秒殺,全局遞增ID等等。大部分的解決方案是基于DB實(shí)現(xiàn)的,Redis為單進(jìn)程單線程模式,采用隊(duì)列模式將并發(fā)訪問變成串行訪問,且多客戶端對(duì)Redis的連接并不存在競(jìng)爭(zhēng)關(guān)系。
    2021-05-05

最新評(píng)論