redis的事件機制

2021-05-26 07:32:28 字數 3055 閱讀 1151

**:   相當清晰

每個cs程式尤其是高併發的網路服務端程式都有自己的網路非同步事件處理庫,redis不例外。

我們從redis啟動的main函式開始,從使用者發出連線鍵入命令開始遍歷網路事件庫所涉及的函式,unix套介面相關函式不表。

首先對幾個最常用物件進行解釋。

//redis啟動的時候(init_server())會建立的乙個全域性使用的事件迴圈結構

typedef struct aeeventloop aeeventloop;

//檔案可讀寫事件

typedef struct aefileevent aefileevent;

//超時時間事件

typedef struct aetimeevent aetimeevent;

//從epoll_wait或者select返回的,已經觸發的檔案事件

typedef struct aefiredevent aefiredevent;

我們來模擬redis server 啟動和使用者鍵入命令的過程,先上圖。

好吧,從main函式開始吧。

// src/redis.c 853

server.el = aecreateeventloop();

建立乙個aeeventloop結構體,成員apidata指向乙個aeapistate物件,如果使用epoll,fd是由epoll_create建立的全域性epoll fd ,events 用於儲存epoll_wait返回的事件組。

// src/redis.c 866

server.ipfd = anettcpserver(server.neterr,server.port,server.bindaddr);

建立監聽。

//   src/redis.c 903

aecreatetimeevent(server.el, 1, servercron, null, null);

註冊乙個時間事件servercron,作用以後再講。

//   src/redis.c 906

aecreatefileevent(server.el,server.ipfd,ae_readable, accepttcphandler,null)

為監聽fd的註冊乙個檔案事件,首先把listenfd和觸發條件epoll_ctl加入到全域性的epoll fd進行監控。再以fd作為檔案事件event陣列index定位,mask填入唯讀,rfileproc填入accepttcphandler函式。

// src/redis.c 1571

aesetbeforesleepproc(server.el,beforesleep);

aeeventloop註冊乙個beforesleep函式,這個函式在主迴圈裡每次會被呼叫,作用以後再講。

// src/ redis.c 1572

aemain()

網路事件庫的核心迴圈函式。

// src/ae.c  379

aecreateloop->beforesleep()

就是上面註冊的beforesleep函式。

// src/ae.c 275

aeprocessevents(eventloop, ae_all_events);

先排程aeapipoll,用epoll_wait處理檔案事件,返回的fd和觸發條件先儲存在eventloop->fired裡,然後根據fired每個事件的的fd,定位到events,根據觸發條件呼叫已經註冊的事件。

檔案事件處理完畢後,接下來就是處理超時時間事件,這裡不表。

假如有個使用者連線上redis,則從redis servere就從上面的aeapipoll的poll_wait返回,產生的唯讀事件會排程上面註冊了accepttcphandler函式。

// src/networking.c 390

accepttcphandler(eventloop, fd, null, ae_readable)

accept返回產生了乙個新連線的fd(這裡省略了很多步驟),需要從新的連線讀取資料,於是為這個fd註冊可讀事件。

// src/networking.c 20

aecreatefileevent(server.el,fd,ae_readable, readqueryfromclient, c)

於是呼叫了aecreatefileevent 為唯讀事件註冊, 這裡的步驟和上面的listen fd 一樣。用epoll_ctl將fd加入到epoll fd裡等待下次epoll_wait,再註冊觸發條件和readqueyfromclient函式,接著aemain()繼續執行等待使用者的資料。

假如使用者在這個連線鍵入redis命令例如:set foo bar,redis server端將會從aeapipoll的epoll_wait返回,和accept一樣的處理方式。返回的fd填入到fired陣列,通過 fired[fd]->fd找到是哪個檔案事件,找到events[fd]->rfielproc這個函式,就是上面註冊的 readqueyfromclient 函式。

//  src/networking.c 816

readqueyfromclient(server.el, fd, null, ae_readable)

這個函式首先會執行read從tcp buffer讀取使用者鍵入的命令(非阻塞io),然後處理buffer,找到對應的command(lookupcommand),接下來執行這個 command(call(c,cmd)),命令執行完畢需要返回結果的時候,會再次註冊乙個檔案事件

// src/networking.c  71

aecreatefileevent(server.el, c->fd, ae_writable, sendreplytoclient, c)

這樣下次迴圈epoll_wait的時候就發現這個fd可寫,於是就會執行sendreplytoclient,講結果傳送給client。

redis的這個網路事件庫是比較標準的網路框架的模式,實現的功能不算多但夠用。

C 的事件機制

c 的事件機制是基於委託實現的。實現乙個事件,要先定義乙個委託型別 class1 然後我們可以使用 和 註冊 移除事件 class1.event1 new mydelegate new myeventargs 在class中引發事件時最好這樣 class1 如果不想宣告自己的委託型別的話,可以使用s...

Remoting的事件機制

概念就不說了,具體參見msdn相關章節 我們為主執行緒方法新增事件,能不斷的引發事件來匯報處理的進度 public class myeventargs public myeventargs int rate public class myobject console.writeline 主線程方法結...

wxWidget的事件機制

wxwidget 的事件機制 wxwidget 通過在編譯期生成靜態的事件表來實現事件類的事件處理。所有想要使用事件處理機制的地方都需要繼承 wxevthandler 類 直接或間接 由於 window 控制項需要處理自身的 ui 時間,故 wxwidget 將實現為 exevthandler 的基...