redis服务器是一个事件驱动程序。可以分为文件事件和时间事件,其中文件事件是服务器和客户端之间连接
套接字的抽象,而时间事件又分为定时事件和周期事件,目前redis 只实现了周期事件.
redis 文件事件是通过select/epoll等这些函数库的包装.
举例如下:
例如我们通过下面这个函数关联事件到fd
static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
aeApiState *state = eventLoop->apidata;
struct epoll_event ee;
//根据fd.mask 来决定是add还是mod操作
int op = eventLoop->events[fd].mask == AE_NONE ?
EPOLL_CTL_ADD : EPOLL_CTL_MOD;
// 注册事件到 epoll
ee.events = 0;
mask |= eventLoop->events[fd].mask; /* Merge old events */
if (mask & AE_READABLE) ee.events |= EPOLLIN;
if (mask & AE_WRITABLE) ee.events |= EPOLLOUT;
ee.data.u64 = 0; /* avoid valgrind warning */
ee.data.fd = fd;
// 将事件注册设置到kernel space
if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1;
return 0;
}
在例如通过下面的函数来获取可执行的时间
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
aeApiState *state = eventLoop->apidata;
int retval, numevents = 0;
// 等待事件ready
retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,
tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1);
// 至少有一个事件ready了
if (retval > 0) {
int j;
// 从这里看到文件事件只有read和write 两种,这里会将这两种事件
// 都加入到fired这个数组中
numevents = retval;
for (j = 0; j < numevents; j++) {
int mask = 0;
struct epoll_event *e = state->events+j;
if (e->events & EPOLLIN) mask |= AE_READABLE;
if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
if (e->events & EPOLLERR) mask |= AE_WRITABLE;
if (e->events & EPOLLHUP) mask |= AE_WRITABLE;
eventLoop->fired[j].fd = e->data.fd;
eventLoop->fired[j].mask = mask;
}
}
// 返回已就绪事件个数
return numevents;
}
服务器在一般情况下只执行servercron一个周期性的时间事件,文件事件和时间事件两种事件之间轮流执行,不会抢占
并且通常情况下时间事件的处理会比设定的时间晚到达一点.
redis中的文件事件和时间事件
最新推荐文章于 2022-07-26 11:42:23 发布