epoll和他的兄弟们

解释一下epoll与select的区别

epoll和select都是linux下的IO多路复用模型,主要用于实现并发服务程序

相对于select/poll来说,epoll能显著提高程序在大量并发连接中只有少量活跃的情况下cpu的利用率,这主要是因为他们使用的数据结构以及工作方式是不同。

select需要read、write、error三个数组来告诉内核监听的事件类型

while(1){
	初始化文件描述符到集合
	将活动句柄加入到文件描述符中
	调用select函数,fd集合拷贝到内核{
		return ready_count;
	}
	然后轮询整个数组找到需要处理的事件进行处理
}

epoll使用event结构体来标记fd的事件类型等等,主要有三个系统调用函数

	//创建一个epoll文件描述符
	epoll_create(int maxfds);
	//添加/修改/删除需要侦听的文件描述符及其事件,实际上是向红黑树中增删改节点
	epoll_ctl
	//接收发生在被侦听的描述符上的,用户感兴趣的IO事件
	epoll_wait(int epfd, epoll_event *events, int max events, int timeout){
	    return ready_list;
	}
	轮询ready_list处理相关事件

select每次调用都要将fd集合从用户态拷贝到内核态
而epoll只需要向内核态拷贝一次即可
结论:epoll内核态与用户态切换次数更少,运行效率更高

select能够管理的文件描述符的数量为一个进程能够打开的文件描述符的数量,在1024左右
而epoll是在高速内存中保存红黑树节点,能够管理的文件描述符数量取决于内存大小,远大于2048,在1G内存中大概是1万左右
结论:epoll更适合大量并发连接

select数据结构是数组,而epoll是红黑树+list
select不断轮询所有的fd集合直到有设备就绪,返回就绪数,随着数组的增大处理效率会降低
而epoll只需要轮询就绪链表直到有数据就绪,这是因为每个fd都会有相应的回调函数,在socket活跃时调用,并将其放入ready_list中,处理效率不会随fd数目增大而降低
总结:epoll的IO处理效率更高更稳定

select在内核将fd消息通知用户空间的时候进行了内存拷贝
epoll通过内核与用户空间mmap同一块内存避免了拷贝,加速了内核与用户空间的消息传递
总结:epoll在内核与用户空间的消息传递的速度上更快

mmap :一种内存映射文件的方法

ET与LT
select采用水平触发方式,如果有fd就绪,如果你不做任何操作内核会继续通知你,这种编程方式出错可能性小一点。
epoll可以采用边缘出发或者水平触发方式,默认是水平触发边缘触发方式在fd就绪后内核只会通知一次,除非该fd不再为就绪状态,这样的话维护的ready_list长度更低,效率更高,但是有可能带来一次不处理以后都不会被处理的问题。

但并不是所有的情况下epoll都是优于select的:
连接数较少而且比较活跃情况下更适合使用select
epoll每个事件都要注册一个回调函数有一定的开销,运行机制更加复杂。

阻塞、非阻塞,同步、异步

内核态和用户态

参考链接:
Epoll在LT和ET模式下的区别以及注意事项.
网络高并发服务器之epoll接口、epoll反应堆模型详解及代码实现.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章