原因1:
引用
Linux內(nèi)核會(huì)給每個(gè)進(jìn)程維護(hù)一個(gè)文件描述符表。而POSIX標(biāo)準(zhǔn)對(duì)于文件描述符進(jìn)行了以下約束:
- fd為0遥巴、1、2分別表示標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和錯(cuò)誤輸出
- 每次新打開(kāi)的fd,必須使用當(dāng)前進(jìn)程中最小可用的文件描述符艾杏。
Redis充分利用了文件描述符的這些特點(diǎn),來(lái)存儲(chǔ)每個(gè)fd對(duì)應(yīng)的事件盅藻。
原因2:
因?yàn)閞edis 是單線程高性能的购桑。
所以redis需要單線程輪詢汹族。
操作系統(tǒng)機(jī)制的輪詢是不太一樣的。
簡(jiǎn)而言之 linxu輪詢用epoll其兴,window 用selector
但是性能上來(lái)說(shuō) epoll是高于selector 的顶瞒。
原因3
redis-windows是由微軟開(kāi)發(fā)的。
Redis不僅支持Linux下的epoll元旬,還支持其他的IO復(fù)用方式榴徐,目前支持如下四種: 1. epoll:支持Linux系統(tǒng) 2. kqueue:支持FreeBSD系統(tǒng)(如macOS) 3. select 4. evport: 支持Solaris
幾個(gè)IO復(fù)用方式使用的判斷順序如下:
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
#ifdef HAVE_EPOLL
#include "ae_epoll.c"
#else
#ifdef HAVE_KQUEUE
#include "ae_kqueue.c"
#else
#include "ae_select.c"
#endif
#endif
#endif
這個(gè)順序其實(shí)也代表了四種IO復(fù)用方式的性能高低。
對(duì)于每種IO復(fù)用方式匀归,只要實(shí)現(xiàn)以下8個(gè)接口就可以正常對(duì)接Redis了:
int aeApiCreate(aeEventLoop *eventLoop);
void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask);
void aeApiResize(aeEventLoop *eventLoop, int setsize);
void aeApiFree(aeEventLoop *eventLoop);
int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask);
void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask);
int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp);
char *aeApiName(void);
在這個(gè)8個(gè)接口下面坑资,其實(shí)底層并沒(méi)有做太多的優(yōu)化,只是簡(jiǎn)單的對(duì)原有API封裝而已穆端。