這篇文章跟大家介紹一下Redis中的文件事件,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
Redis 伺服器是事件驅動程序,分為檔案事件
和時間事件
【相關推薦:Redis視頻教學】
它們都被封裝到aeEventLoop
結構體中
typedef struct aeEventLoop { int stop; // 标识事件是否结束 aeFileEvent *events; // 文件事件数组,存储已注册的文件事件 aeFireEvent *fired; // 存储被触发的文件事件 aeTimeEvent *timteEventHead; // 多个时间事件形成的链表 void *apidata; // I/O模型的封装 aeBeforeSleepProc *beforesleep; // 进程阻塞前执行 aeBeforeSleepProc *aftersleep; // 进程被唤醒后执行 } aeEventLoop;
事件驅動程式其實也是透過while/for
循環,循環等待事件的發生
while (! eventLoop->stop) { if (eventLoop->beforesleep != NULL) eventLoop->beforesleep(eventLoop) aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP); }
aeProcessEvents
為事件處理主函數
select/epoll/kqueue等,不同的作業系統不同的實作。
epoll為例,它是 Linux 核心為處理大量並發網路連線而提出解決方案。
epoll提供3個API
int epoll_create(int size) // size 告知内核程序期望注册的网络连接数目,Linux 2.6.8后改为内核动态分配 // 返回参数是 epoll 专用的文件描述符
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) // epfd 函数 epoll_create 返回的 epoll 文件描述符 // op 操作类型 EPOLL_CTL_ADD:注册事件; EPOLL_CTL_MOD:修改网络连接事件; EPOLL_CTL_DEL:删除事件 // fd 网络连接的 socket 文件描述符 // event 需要监控的事件
int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout) // epfd 函数epoll_create返回的epoll文件描述符 // epoll_event 作为输出参数使用,用于回传已触发的事件数组 // maxevents 每次能处理的最大事件数目 // timeout epoll_wait 函数阻塞超时时间,如果超过 timeout 时间还没有事件发生,函数就不再阻塞直接返回;当 timeout 等于0是函数立即返回,timeout 等于-1时函数一直阻塞到有事件发生
// 对应 epoll_create static int aeApiCreate(aeEventLoop *eventLoop) // 对应 epoll_ctl 添加事件 static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) // 对应 epoll_ctl 删除事件 static int aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) // 对应 epoll_wait static int aeApiPool(aeEventLoop *eventLoop, struct timeval *tvp)回想一下上面提到的
eventLoop結構體,其成員apidata 指向4種I/O多路復用模型物件;events 儲存需要監控的事件數組,以socket 檔案描述符作為數組索引存取元素;fired 儲存已觸發的事件數組。
typedef struct aeFileEvent { int mask; // 文件事件类型 AE_READABLE 可读事件;AE_WRITEABLE 可写事件 aeFileProc *rfileProc; // 读事件处理函数指针 aeFileProc *wfileProc; // 写事件处理函数指针 void *clientData; // 指向对应的客户端对象 } aeFileEvent;看看建立檔案事件aeCreateFileEvent 的實作
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 伺服器會透過建立各類檔案事件來處理事務,例如:
aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler, NULL);
aeCreateFileEvent(server.el, fd, AE_READABLLE, readQueryFromClient, c);
aeCreateFileEvent(server.el, c->fd, AE_READABLLE, sendReplyToClient, c);
aeProcessEvents函數來控制。在其中,執行文件事件會出現阻塞情況(epoll_wait),如果阻塞事件太長了,會妨礙到時間事件(定時)的執行,為避免這種情況,在實現文件事件時傳入的等待時間,是計算最早發生的時間事件所得到的
int aeProcessEvents(aeEventLoop *eventLoop, int flags) { shortest = aeSearchNearestTimer(eventLoop); long long ms = (shortest->when_sec - now_sec) * 1000 + \ shortest->when_ms - now_ms; // 阻塞事件发生 numevents = aeApiPoll(eventLoop, ms); for (j=0; j < numevents; j++) { aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j]].fd]; // 处理文件事件,即根据类型执行rfileProc或wfileProc } // 处理时间事件 processed += processTimeEvents(eventLoop); }
aeMain 函數透過呼叫aeProcessEvents 函數來進行檔案事件和時間事件的調度和執行。 aeEventLoop 中記錄了事件相關的資訊。首先透過aeSearchNearestTimer 函數取得最短的時間事件的執行時間間隔n,然後呼叫aeApiPoll 函數取得監聽到的套接字,最後執行與套接字向對應的事件處理函數rfileProc 和wfileProc,最後再執行時間事件函數processTimeEvents 。 一次完整的客戶端與服務端連接事件:
更多程式相關知識,請造訪:程式設計影片! !
以上是一文聊聊Redis中的epoll和檔案事件的詳細內容。更多資訊請關注PHP中文網其他相關文章!