基于Socket通讯的反应堆模型
反应堆是基于epoll的IO多路非阻塞模型,来实现的事件驱动,让我们按照递进的顺序进行分析,先来比较一下epoll非阻塞模型相对于多线程的优势所在。
一.多线程与epoll非阻塞
在理解Linux下的多线程模型与异步IO模型时,一定要理解线程与阻塞的开销其实是很大的,下面通过Linux下的测试来证明这一点:为了方便测试,让我们以Shell中的进程为例。
首先开启一个阻塞进程:read
然后使用ps -aux | grep read 查看一下它占用的资源:
VSZ(Virtual Memory Size),虚拟内存大小,表明了该进程可以访问的所有内存,包括被交换的内存和共享库内存。
RSS( Resident Set Size )常驻内存集合大小,表示相应进程在RAM中占用了多少内存,并不包含在SWAP中占用的虚拟内存。即使是在内存中的使用了共享库的内存大小也一并计算在内,包含了完整的在stack和heap中的内存。
RSS更侧重于描述线程(进程)所实际占用的物理资源,你看,这样一个本身堆栈资源占用很小,更没有开辟共享内存的进行就占用了如此多的资源。
二.反应堆
顾名思义反应堆其名所要表达的含义就是速度快,那么它是怎样在epoll非阻塞IO模型的基础上提高效率的呢,主要有以下几点原因:
1.反应堆使用自定义的结构体myevent_s对epoll操作进行了封装。添加了节点创建的时间点以提供链接检测;添加了回调函数以处理文件描述符所触发的事件。
struct myevent_s {
int fd; //要监听的文件描述符
int events; //对应的监听事件
void *arg; //泛型参数
void (*call_back)(int fd, int events, void *arg); //回调函数
int status; //是否在监听:1->在红黑树上(监听), 0->不在(不监听)
char buf[BUFLEN];
int len;
long last_active; //记录每次加入红黑树 g_efd 的时间值
};
成员变量1 2 3 均为回调函数call_back的参数,参数5 表示文件描述符的状态,6 7为一个数组,最后的last_active是表示此文件描述符加入红黑树的时间,这个在前面的介绍中也提到过。
重要的是,arg参数传入的恰恰就是这个结构体本身的指针。