午夜无码人妻aⅴ大片色欲张津瑜,国产69久久久欧美黑人A片,色妺妺视频网,久久久久国产综合AV天堂

怎么理解Redis中的epoll和文件事件

這篇文章主要講解了“怎么理解redis中的epoll和文件事件”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“怎么理解Redis中的epoll和文件事件”吧!

創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站與策劃設(shè)計(jì),越秀網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10余年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:越秀等地區(qū)。越秀做網(wǎng)站價(jià)格咨詢:18980820575

怎么理解Redis中的epoll和文件事件

事件驅(qū)動(dòng)

Redis 服務(wù)器是事件驅(qū)動(dòng)程序,分為文件事件時(shí)間事件

  • 文件事件:socket 的可讀可寫事件

  • 定時(shí)任務(wù)

它們都被封裝到aeEventLoop結(jié)構(gòu)體中

typedef struct aeEventLoop {
	int stop; // 標(biāo)識(shí)事件是否結(jié)束
	aeFileEvent *events; // 文件事件數(shù)組,存儲(chǔ)已注冊(cè)的文件事件
	aeFireEvent *fired; // 存儲(chǔ)被觸發(fā)的文件事件
	aeTimeEvent *timteEventHead; // 多個(gè)時(shí)間事件形成的鏈表
	void *apidata; // I/O模型的封裝
	aeBeforeSleepProc *beforesleep; // 進(jìn)程阻塞前執(zhí)行
	aeBeforeSleepProc *aftersleep; // 進(jìn)程被喚醒后執(zhí)行
} aeEventLoop;

事件驅(qū)動(dòng)程序?qū)嶋H上也是通過(guò)while/for循環(huán),循環(huán)等待事件的發(fā)生

while (! eventLoop->stop) {
	if (eventLoop->beforesleep != NULL)
		eventLoop->beforesleep(eventLoop)
	aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);
}

aeProcessEvents為事件處理主函數(shù)

epoll

Redis 客戶端通過(guò) TCP socket 與服務(wù)端交互,文件事件指的就是 socket 的可讀可寫事件。一般使用非阻塞模式,相關(guān)的 I/O 多路復(fù)用有select/epoll/kqueue等,不同的操作系統(tǒng)不同的實(shí)現(xiàn)。

epoll為例,它是 Linux 內(nèi)核為處理大量并發(fā)網(wǎng)絡(luò)連接而提出解決方案。epoll提供3個(gè) API

  • epoll_create 創(chuàng)建一個(gè) epoll 專用的文件描述符,用于后續(xù) epoll 相關(guān) API 調(diào)用

int epoll_create(int size)
// size 告知內(nèi)核程序期望注冊(cè)的網(wǎng)絡(luò)連接數(shù)目,Linux 2.6.8后改為內(nèi)核動(dòng)態(tài)分配
// 返回參數(shù)是 epoll 專用的文件描述符
  • epoll_ctl 函數(shù)向 epoll 注冊(cè)、修改或刪除需要監(jiān)控的事件

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
// epfd 函數(shù) epoll_create 返回的 epoll 文件描述符
// op 操作類型 EPOLL_CTL_ADD:注冊(cè)事件; EPOLL_CTL_MOD:修改網(wǎng)絡(luò)連接事件; EPOLL_CTL_DEL:刪除事件
// fd 網(wǎng)絡(luò)連接的 socket 文件描述符
// event 需要監(jiān)控的事件
  • epoll_wait 函數(shù)會(huì)會(huì)阻塞進(jìn)程,直到監(jiān)控的若干網(wǎng)絡(luò)連接有事件發(fā)生

int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout)
// epfd 函數(shù)epoll_create返回的epoll文件描述符
// epoll_event 作為輸出參數(shù)使用,用于回傳已觸發(fā)的事件數(shù)組
// maxevents 每次能處理的最大事件數(shù)目
// timeout epoll_wait 函數(shù)阻塞超時(shí)時(shí)間,如果超過(guò) timeout 時(shí)間還沒(méi)有事件發(fā)生,函數(shù)就不再阻塞直接返回;當(dāng) timeout 等于0是函數(shù)立即返回,timeout 等于-1時(shí)函數(shù)一直阻塞到有事件發(fā)生

文件事件

Reids 沒(méi)有直接使用 epoll 的 API,而是同時(shí)支持4種I/O多路復(fù)用模型,對(duì)這些模型的 API 進(jìn)行了封裝。然后在編譯階段檢查操作系統(tǒng)支持的I/O多路復(fù)用模型,并按照策略來(lái)決定復(fù)用那張模型。

還是以 epoll 為例,Redis 進(jìn)行了如下封裝

// 對(duì)應(yīng) epoll_create
static int aeApiCreate(aeEventLoop *eventLoop)

// 對(duì)應(yīng) epoll_ctl 添加事件
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask)
// 對(duì)應(yīng) epoll_ctl 刪除事件
static int aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask)

// 對(duì)應(yīng) epoll_wait
static int aeApiPool(aeEventLoop *eventLoop, struct timeval *tvp)

回憶一下上面提到的eventLoop結(jié)構(gòu)體,其成員 apidata 指向4種I/O多路復(fù)用模型對(duì)象;events 存儲(chǔ)需要監(jiān)控的事件數(shù)組,以 socket 文件描述符作為數(shù)組索引存取元素;fired 存儲(chǔ)已觸發(fā)的事件數(shù)組。

文件事件的結(jié)構(gòu)體定義如下:

typedef struct aeFileEvent {
	int mask; // 文件事件類型 AE_READABLE 可讀事件;AE_WRITEABLE 可寫事件
	aeFileProc *rfileProc; // 讀事件處理函數(shù)指針
	aeFileProc *wfileProc; // 寫事件處理函數(shù)指針
	void *clientData; // 指向?qū)?yīng)的客戶端對(duì)象
} aeFileEvent;

看一下創(chuàng)建文件事件 aeCreateFileEvent 的實(shí)現(xiàn)

int aeCreateFileEvent (aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData) {
	aeFileEvent *fe = &eventLoop->evnts[fd];
	if (aeApiAddEvent(eventLoop, fd, mask) == -1)
		return AE_ERR;
	fe->mask |= mask;
	if (mask & AE_READABLE) fe->rfileProc = proc;
	if (mask & AE_WRITABLE) fe->wfileProc = proc;
	fe->clientData = clientData;
	return AE_OK;
}

Redis 服務(wù)器會(huì)通過(guò)創(chuàng)建各類文件事件來(lái)處理事務(wù),比如:

  • 啟動(dòng)時(shí)創(chuàng)建 socket 并監(jiān)聽(tīng),等待客戶端連接

aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler, NULL);
  • 客戶端與服務(wù)器建立 socket 連接之后,服務(wù)器會(huì)等待客戶端的命令請(qǐng)求

aeCreateFileEvent(server.el, fd, AE_READABLLE, readQueryFromClient, c);
  • 服務(wù)器處理完客戶端的命令請(qǐng)求之后,命令回復(fù)會(huì)暫時(shí)緩存在client結(jié)構(gòu)體的buf緩沖區(qū),待客戶端文件描述符的可寫事件發(fā)生時(shí),才會(huì)真正往客戶端發(fā)送命令回復(fù)

aeCreateFileEvent(server.el, c->fd, AE_READABLLE, sendReplyToClient, c);

Redis 所有事件的執(zhí)行都是通過(guò)aeProcessEvents函數(shù)來(lái)控制。在其中,執(zhí)行文件事件會(huì)出現(xiàn)阻塞情況(epoll_wait),如果阻塞事件太長(zhǎng)了,會(huì)妨礙到時(shí)間事件(定時(shí))的執(zhí)行,為避免出現(xiàn)這種情況,在實(shí)現(xiàn)文件事件時(shí)傳入的等待時(shí)間,是計(jì)算最早發(fā)生的時(shí)間事件得到的

int aeProcessEvents(aeEventLoop *eventLoop, int flags) {
	shortest = aeSearchNearestTimer(eventLoop);
	long long ms = (shortest->when_sec - now_sec) * 1000 + \
		shortest->when_ms - now_ms;

	// 阻塞事件發(fā)生
	numevents = aeApiPoll(eventLoop, ms);

	for (j=0; j < numevents; j++) {
		aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j]].fd];
		// 處理文件事件,即根據(jù)類型執(zhí)行rfileProc或wfileProc
	}

	// 處理時(shí)間事件
	processed += processTimeEvents(eventLoop);
}

總結(jié)

現(xiàn)在我們來(lái)整體看一下 Redis 服務(wù)器相應(yīng)命令的流程

怎么理解Redis中的epoll和文件事件

aeMain 函數(shù)通過(guò)調(diào)用 aeProcessEvents 函數(shù)來(lái)進(jìn)行文件事件和時(shí)間事件的調(diào)度和執(zhí)行。aeEventLoop 中記錄了事件相關(guān)的信息。首先通過(guò) aeSearchNearestTimer 函數(shù)獲取最短的時(shí)間事件的執(zhí)行時(shí)間間隔n,然后調(diào)用 aeApiPoll 函數(shù)獲取監(jiān)聽(tīng)到的套接字,最后執(zhí)行與套接字向?qū)?yīng)的事件處理函數(shù) rfileProc 和 wfileProc,最后再執(zhí)行時(shí)間事件函數(shù) processTimeEvents。

一次完整的客戶端與服務(wù)端連接事件:

  • 器監(jiān)聽(tīng)套件字的 AE_READABLE 事件,當(dāng)客戶端發(fā)送連接請(qǐng)求產(chǎn)生 AE_READABLE  事件,服務(wù)端會(huì)對(duì)客戶端的連接請(qǐng)求進(jìn)行應(yīng)答,將客戶端套接字的 AE_READABLE 事件與命令請(qǐng)求處理函數(shù)(aeFileProc),客戶端可以向服務(wù)端發(fā)送命令請(qǐng)求了

  • 端向服務(wù)端發(fā)送一個(gè)命令請(qǐng)求,客戶端套接字將產(chǎn)生 AE_READABLE 事件,引發(fā)命令處理器去執(zhí)行,執(zhí)行命令將產(chǎn)生相應(yīng)的命令回復(fù),服務(wù)端將客戶端套接字的 AE_WRITABLE 事件與命令回復(fù)處理函數(shù)(aeFileProc)關(guān)聯(lián)

  • 端嘗試讀取命令回復(fù)時(shí),客戶端套接字將產(chǎn)生 AE_WRITABLE 事件,觸發(fā)命令回復(fù)處理器執(zhí)行,當(dāng)命令回復(fù)處理器將命令回復(fù)全部寫入套接字之后,服務(wù)器就會(huì)接觸客戶端套接字的 AE_WRITABLE 事件與命令回復(fù)處理函數(shù)(aeFileProc)之間的關(guān)聯(lián)

感謝各位的閱讀,以上就是“怎么理解Redis中的epoll和文件事件”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)怎么理解Redis中的epoll和文件事件這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

名稱欄目:怎么理解Redis中的epoll和文件事件
轉(zhuǎn)載來(lái)于:http://www.ekvhdxd.cn/article14/jcgdde.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、虛擬主機(jī)、軟件開(kāi)發(fā)、企業(yè)建站動(dòng)態(tài)網(wǎng)站、建站公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司